-
Notifications
You must be signed in to change notification settings - Fork 95
What entity style to use?
GenericServices classified entity types into two main styles:
- 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.
- 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.
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).
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).
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.