1

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?

2
  • Why would it be an antipattern? Aug 3, 2017 at 16:20
  • @Ben Aaronson, not sure really. Maybe from a separation of concerns perspective? I have added the question (see last part) in case it helps.
    – w0051977
    Aug 3, 2017 at 16:24

3 Answers 3

1

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.

24
  • So it is reasonable to add your own methods to these classes i.e. even the ones' created by EF (in the case of database first)?
    – w0051977
    Aug 3, 2017 at 17:05
  • @w0051977: I wouldn't do that. Just transfer the data from your business objects to the EF objects, and let EF deal with its own objects on its own terms. Put any logic you require into the business objects. Aug 3, 2017 at 17:06
  • @Robert Harvey, is your comment relating to Database First only or both Database First and Code First?
    – w0051977
    Aug 3, 2017 at 17:08
  • 1
    @w0051977: You can't split partial classes across assembly boundaries. If you want to do that, you're better off treating the EF classes as DTO's and using business classes in your business logic layer instead. If you follow domain-design principles, you shouldn't need Person classes in your business logic. Instead, you'll have classes that represent business operations which accept EF Person objects as parameters. Aug 3, 2017 at 17:25
  • 1
    @w0051977: This is more than just a naming problem. My instinct is to answer your last question with "Persons don't place orders. An order management object places orders on behalf of the person." See here for some further insight into your overall problem. Aug 3, 2017 at 17:43
1

Essentially they are both the same. You should wrap your Person object the same way you wrap your dbPerson.

Although you can use 'POCO' EF classes for the simplest of cases, the EF 'Code First' objects will inevitably require data annotations that reference the Entity Framework library, once you start doing anything complicated. This makes them unsuitable to use for domain objects.

If you are unlikely to move away from EF and don't reuse your domain objects in programs that wont be able to reference the EF nuget package, then you can get away with ignoring this problem.

But really if you want to stick with the repository pattern where your objects are cleanly separated from the database, EF is all but useless, you are better off manually coding the SQL and mapping datareaders.

0

1) Is this a benefit of Code First?

More or less that is. The benefit of Code-First seem to be that the persistent data model is generated "on the fly" according with the application data model premises. So, one less model -and code- to maintain.

Consider the db data model to be the physical model and the domain data model the logical model. Both are not necessarily the same.

However, this is exactly what Code-first EF does for you. It removes the need of thinking in both models. The persistent model is described by the domain data model itself, rather than implemented. So essentially there's only one model in your code base. The domain data model.

Code-first follows its own conventions. Mainly based on configurations, the names of the classes, methods, etc...

Somewhat similar to convention over configuration.

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

No. Just the opposite. Code-first EF encourage you to focus on the logic rather than on the persistence. However, It doesn't not say you how to do it. You might end up modelling POCOS anyways. You still need to be familiar with DDD and its premises.

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

Not necessarily, but it's unlikely to happen. Database-first models are prone to be row mappers (POCOS, DTO, whatever). However, if you found the way to make your code-first entities "smart", you should be able to do the same with database-first. Ultimatelly, the model doesn't depends on the tools we use. Or it should not.

The difference between CF and DBF is that DBF forces you to map and implement the persistent model, while CF does it "magically on the fly" for you.

One less abstraction to be worried about.

Note: On both approaches, -CF and DBF- repositories should return domain entities. Following CF this's inmediate, following DBF take us to map the persistent model to the domain model (if any). The application layer doesn't need to know the shape of the data on the persistence layer.

7
  • Thanks. This is what I was thinking when I asked the question. On that basis I think that code first is "better" than database first from a DDD perspective. You can just map to the Domain Objects directly. Have I understood you correctly?
    – w0051977
    Aug 3, 2017 at 19:34
  • Yes. But the line between CF and DBF is blurred. As I commented, we still may end up coding POCOS with both approaches. If you are going with CF, model as there were no persistence. Focus on the logic first. Later, follow CF conventions for persisting what should be persisted.
    – Laiv
    Aug 3, 2017 at 19:38
  • Are you saying with a CF approach then you just map EF to domain objects?
    – w0051977
    Aug 3, 2017 at 19:55
  • Nop. I'm saying do model as there were no EF at all. Be pure DDD. Later decide what data of the model need to be persisted. Finally, look at the CF conventions to make the persistence you need possible. For CF, the persistence are mere implementation details.
    – Laiv
    Aug 3, 2017 at 20:00
  • So are you saying; map to the EF classes and then the domain classes? Thanks.
    – w0051977
    Aug 3, 2017 at 20:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.