Skip to content

What entity style to use?

Jon P Smith edited this page Apr 10, 2018 · 7 revisions

GenericServices classified entity types into two main styles:

  1. Standard styled: These are entity classes that can be created/updated by setting their properties. Useful for simple entity classes where there is no business logic or special relationships.
  2. DDD-styled: These are entity classes where you create/update by public methods or constructors. Useful for entity classes that have business rules on how to create/update, and may be the root of a set of aggregate entity types (read this part of the article for more on these DDD terms).

If you are not familiar with Domain-Driven Design (DDD) entity classes I recommend you read the article Creating Domain-Driven Design entity classes with Entity Framework Core first.

Which style of entity class should I use?

Standard-styled entity classes

The simplest, and most known style, is standard-style. This has a public, parameterless constructor and all the properties have public setters. Here is an example

public class Author
{
    //public, parameterless constructor 
    public Author() { }

    //properties with public get and set
    public int AuthorId { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public ICollection<BookAuthor> BooksLink { get; set; }
}

If you already have these then that's fine - GenericServices can work with them (it uses AutoMapper inside to read/write this style of entity classes).
The down side is you MUST be careful to add [ReadOnly(true)] attributes to and DTO properties that are read, but should not be written back to the database (see DTO - ReadOnly attribute for more on this).

DDD-styled entity classes

The DDD-styled entity classes are a bit more complicated, with any create or update done via methods/constructors inside the entity class. Here is an example

public class Order
{
    private HashSet<LineItem> _lineItems;

    //private, parameterless constructor used by EF Core
    private Order() { }

    //properties have private setter so they can't be updated
    public int OrderId { get; private set; }
    public DateTime DateOrderedUtc { get; private set; }
    public string CustomerName { get; private set; }
    //This one-to-many relationship is done via a EF Core backing field
    public IEnumerable<LineItem> LineItems => _lineItems?.ToList();

    public static IStatusGeneric<Order> CreateOrder(
        string customerName, IEnumerable<OrderBooksDto> bookOrders)
    {
        var status = new StatusGenericHandler<Order>();
        var order = new Order
        {
            CustomerName = customerName
        };

        byte lineNum = 1;
        order._lineItems = new HashSet<LineItem>(bookOrders
            .Select(x => new LineItem(x.numBooks, x.ChosenBook, lineNum++)));
        if (!order._lineItems.Any())
            status.AddError("No items in your basket.");

        return status.SetResult(order); //The Result will return default(T) if there are errors
    }
}

There are some advantages over standard-styled entity classes:

  • The DDD-style controls access. There is no possibility of changing a property by accident. Each change is done by a named method or constructor with defined parameters.
  • The DDD-style is DRY (don’t repeat yourself). You might need to create a Book instance in a few places. By putting all the code in the Book’s constructor then you don’t have to repeat it in different places.
  • The DDD-style hides complex entity rules. For instance the creating of an entity might require certain properties to not be null, and set in a specific way. This can be hidden inside the entity class.
  • The DDD-style hides the setup of the aggregate entities. DDD has the concept of aggregate entities that should only be updated by the parent entity (called the root entity). This keeps the root entity and its aggregates in step.
  • The DDD-style means the property setters can be private. One reason for using a DDD-style is to “lock down” the entity, i.e. you cannot alter any of the properties or relationships directly.

GenericServices will match the properties in the DTO to the parameters in the methods/constructors and then build LINQ commands to call the method/constructor (which is very fast).

Its your choice

I'm not here to preach, but I have build GenericServices to support both types. You choose which style you want to use.

Personally I expect to use DDD-style for the complex entities in my database, but some simple entities, like say an address or a person's details, I most likely would build in standard-style. That way I get the advantages of the DDD-style where I need it, but I can quickly build standard style where the entity has no rules/complication in it.