13

I have several concerns when trying to do DDD development with EF 4.2 (or EF 4.1) code first. I've done some extensive research but haven't come up with concrete answers for my specific concerns. Here are my concerns:

  1. The domain cannot know about the persistence layer, or in other words the domain is completely separate from EF. However, to persist data to the database each entity must be attached to or added to the EF context. I know you are supposed to use factories to create instances of the aggregate roots so the factory could potentially register the created entity with the EF context. This appears to violate DDD rules since the factory is part of the domain and not part of the persistence layer. How should I go about creating and registering entities so that they correctly persist to the database when needed to?

  2. Should an aggregate entity be the one to create it's child entities? What I mean is, if I have an Organization and that Organization has a collection of Employee entities, should Organization have a method such as CreateEmployee or AddEmployee? If not where does creating an Employee entity come in keeping in mind that the Organization aggregate root 'owns' every Employee entity.

  3. When working with EF code first, the IDs (in the form of identity columns in the database) of each entity are automatically handled and should generally never be changed by user code. Since DDD states that the domain is separate from persistence ignorance it seems like exposing the IDs is an odd thing to do in the domain because this implies that the domain should handle assigning unique IDs to newly created entities. Should I be concerned about exposing the ID properties of entities?

I realize these are kind of open ended design questions, but I am trying to do my best to stick to DDD design patterns while using EF as my persistence layer.

Thanks in advance!

Jayantha Lal Sirisena
  • 21,216
  • 11
  • 71
  • 92
Alex Jorgenson
  • 891
  • 1
  • 13
  • 17

2 Answers2

24

On 1: I'm not all that familiar with EF but using the code-first/convention based mapping approach, I'd assume it's not too hard to map POCOs with getters and setters (even keeping that "DbContext with DbSet properties" class in another project shouldn't be that hard). I would not consider the POCOs to be the Aggregate Root. Rather they represent "the state inside an aggregate you want to persist". An example below:

// This is what gets persisted
public class TrainStationState {
  public Guid Id { get; set; }
  public string FullName { get; set; }
  public double Latitude { get; set; }
  public double Longitude { get; set; }

  // ... more state here
}

// This is what you work with
public class TrainStation : IExpose<TrainStationState> { 
  TrainStationState _state;

  public TrainStation(TrainStationState state) {
    _state = state;
    //You can also copy into member variables
    //the state that's required to make this
    //object work (think memento pattern).
    //Alternatively you could have a parameter-less
    //constructor and an explicit method
    //to restore/install state.
  }

  TrainStationState IExpose.GetState() {
    return _state;
    //Again, nothing stopping you from
    //assembling this "state object"
    //manually.
  }

  public void IncludeInRoute(TrainRoute route) {
    route.AddStation(_state.Id, _state.Latitude, _state.Longitude);
  }
}

Now, with regard to aggregate life-cycle, there are two main scenario's:

  1. Creating a new aggregate: You could use a factory, factory method, builder, constructor, ... whatever fits your needs. When you need to persist the aggregate, query for its state and persist it (typically this code doesn't reside inside your domain and is pretty generic).
  2. Retrieving an existing aggregate: You could use a repository, a dao, ... whatever fits your needs. It's important to understand that what you are retrieving from persistent storage is a state POCO, which you need to inject into a pristine aggregate (or use it to populate it's private members). This all happens behind the repository/DAO facade. Don't muddle your call-sites with this generic behavior.

On 2: Several things come to mind. Here's a list:

  1. Aggregate Roots are consistency boundaries. What consistency requirements do you see between an Organization and an Employee?
  2. Organization COULD act as a factory of Employee, without mutating the state of Organization.
  3. "Ownership" is not what aggregates are about.
  4. Aggregate Roots generally have methods that create entities within the aggregate. This makes sense because the roots are responsible for enforcing consistency within the aggregate.

On 3: Assign identifiers from the outside, get over it, move on. That does not imply exposing them, though (only in the state POCO).

Yves Reynhout
  • 2,982
  • 17
  • 23
  • Perfect! That's a great explanation of the things I am struggling with. In all my research I don't remember seeing this kind of solution where the state of the domain object is split out. I'll mess around with this new design and thanks for hitting on all of my points. +2 if I could. – Alex Jorgenson Dec 19 '11 at 22:22
  • Yves, I like this approach - I think - but are you able to expand on your code to include navigation properties? Do you have any links to more info about the pattern you are using there? – saille Dec 23 '11 at 00:24
  • @saille I'm sure others have used this technique before. So I don't consider this special. Wrt navigation (aka lazy-load) properties, just don't. There's no reason for navigation in the traditional sense when modeling aggregates. I encourage you to have a look at Vaughn's whitepapers on aggregate design over at domaindrivendesign.org. – Yves Reynhout Dec 25 '11 at 19:47
  • @YvesReynhout is there a name for this pattern? I call it "Toreador" but I guess there's already a name for it. – ZioBrando Oct 29 '12 at 13:51
  • @Alberto: absolutely no idea. Memento meets Entity? – Yves Reynhout Nov 07 '12 at 21:49
  • 1
    What about Anemic Domain Model? What you're doing here is making POCO anemic and turning aggegates into transaction scripts over them... "You can also copy into member variables" is even worse. This innocently-looking comments really means: I'll do by hand what Entity Framework was supposed to do automatically. – Bartłomiej Szypelow Mar 01 '13 at 14:14
  • Recognizing things are not going to get any better with this tech and stop fooling oneself that those entities are domain objects is what I had in mind. If you think you can achieve persistence ignorance with EF, be my guest to ignore this advice. Clearly it's not for you. If you think aggregates are transaction script over state objects, you're not really getting the point IMO. While you can design loosely coupled models with EF, that's seldomly where you'll end up. Making state private, transforming primitives into value objects/entities, having state in a write convenient state is what this – Yves Reynhout Mar 02 '13 at 23:00
  • is all about. You're better off with NHibernate in that department, IMO. But if you do want to deal with EF (at the time of writing the original statement), at least you know what you're getting into. Better make things explicit at that point, rather than sprinkling getters all over the place to please persistance. I'd argue that more freedom ensues. But given your tone of comment, we'll never see eye to eye on this. – Yves Reynhout Mar 02 '13 at 23:09
2
  1. The main problem with EF-DDD compatibility seems to be how to persist private properties. The solution proposed by Yves seems to be a workaround for the lack of EF power in some cases. For example, you can't really do DDD with Fluent API which requires the state properties to be public. I've found only mapping with .edmx files allows you to leave Domain Entities pure. It doesn't enforce you to make things publc or add any EF-dependent attributes.

  2. Entities should always be created by some aggregate root. See a great post of Udi Dahan: http://www.udidahan.com/2009/06/29/dont-create-aggregate-roots/ Always loading some aggregate and creating entities from there also solves a problem of attaching an entity to EF context. You don't need to attach anything manually in that case. It will get attached automatically because aggregate loaded from the repository is already attached and has a reference to a new entity. While repository interface belongs to the domain, repository implementation belongs to the infrastructure and is aware of EF, contexts, attaching etc.

  3. I tend to treat autogenerated IDs as an implementation detail of the persistent store, that has to be considered by the domain entity but shouldn't be exposed. So I have a private ID property that is mapped to autogenerated column and some another, public ID which is meaningful for the Domain, like Identity Card ID or Passport Number for a Person class. If there is no such meaningful data then I use Guid type which has a great feature of creating (almost) unique identifiers without a need for database calls. So in this pattern I use those Guid/MeaningfulID to load aggregates from a repository while autogenerated IDs are used internally by database to make a bit faster joins (Guid is not good for that).

Bartłomiej Szypelow
  • 2,121
  • 15
  • 17