C# – Return domain objects from the repository

cdomain-driven-design

I am more experienced with the Database First approach for Entity Framework. I am currently looking at a Code First project, which returns domain model objects from the repository.

Database First

Please see the code below, which is a Database First repository method I created:

public dbPerson getPersonByID(int personID)
        {
            return _dbContext.Set<dbPerson>()
                   .Where(x => x.ID == personID);  
        }

dbPerson is a class created by Entity Framework Database First. The application service calls getPersonByID (contained in repository) and maps the dbPerson class returned by the repository to Person (Domain class). The Person domain object then calls its own methods.

Code First

I am now looking at a code first implementation that appears to call the database and return a domain object i.e. the repository looks like this:

public Person getPersonByID(int personID)
        {
            return _dbContext.Set<Person>()
                   .Where(x => x.ID == personID);  
        }

In this case; there is no need to map dbPerson to Person in the application service (as there was in my Database First example).

Question(s)

1) Is this a benefit of Code First?

2) Is it an anti pattern to put domain logic in a code first EF entity?

3) Is it an anti pattern to put domain logic in a database first EF entity? Are these classes suppose to be treated as simple DTOs i.e. with no methods?

Best Answer

It depends. Is the Person class a plain old C# object when instantiated? I'm not super familiar with EF but in other frameworks like Doctrine or Hibernate you can rely on the framework to instantiate and return a plain old object that doesn't have any framework magic in it.

If that's the case, and there's nothing about the object or class that ties it to the persistence framework like an inheritance hierarchy, then yes I think it's perfectly reasonable to return it from a repository.

From the comments below, I'd also add the following. I realise that some of these ideas may be swimming against the tide a little bit.

The idea of code-first vs. db-first is basically a relic inherent in the age of EF and the best practice evolution around ORMs. Particularly, with DDD, you'd always choose code-first and only use db-first when you have a legacy DB that you need to integrate with a new domain / application layer. In that sense, when using DDD, I'd consider that the EF db-first classes should constitute the input to your Anti-Corruption Layer of your domain.

However, with the code-first paradigm the issue is different. In that scenario, with ORM frameworks like EF, you don't want to mix your persistence framework with your domain code and that instinct is quite right.

However it raises the issue of what constitutes "mixing", and whether or not using plain old objects that the framework knows how to hydrate from the database is enough of a separation of concerns. My view is that if the hydrated objects are plain old objects that can standalone from the framework, then you are still separating your concerns. The reason for this is that the objects returned from the repositories are abstracted from the ORM: client code of the repositories can't tell the difference if the plain old object came from the ORM or some other thing like a factory or other persistence mechanism, like a cache.

Some frameworks might require you to make your code-first classes inherit from a framework-provided parent class, or might use reflection or some other run-time dynamism to add methods to your code-first classes, for example to support an ActiveRecord-style API. In those cases, even with code first, I would say it's probably okay to have your own plain domain classes. But you are adding complexity for the extra abstraction.

Some ORM frameworks, likely EF as well, will provide proxy-type classes for related entities. So, for example, if you have an Employee entity class that composes a Person entity class, and they are connected to each other via a foreign-key relationship in the database, when you obtain an Employee object from the repository, depending on what kind of database query was used and the configuration of the relationship, the related Person entity data will be lazily loaded from the database. In that case, when you call getPerson() on the Employee object, there's proxy object returned instead of the real Person object, and the proxy object will fault in the Person data the first time you try to read the data from the object.

Personally I don't feel that the use of proxy objects in this way, even though it's part of the framework's magic, should cause you to create separate domain objects. Again, if you were to swap out ORMs or use a different persistence store, the repositories could encapsulate / delegate all of that. Concerns about coupling the persistence framework and the domain model can be alleviated in the repositories.