43

I am wondering because if it is, why does Entity Framework not offer logic to create a new object with the same properties to transfer data between layers?

I use the entity objects that I generate with the entity framework.

user2484998
  • 549
  • 1
  • 4
  • 4
  • 3
    I think this is a good question but I can't really tell because it's so hard to read I'm not sure how to fix it. Please edit your question. – candied_orange Jun 02 '17 at 19:04
  • 1
    @CandiedOrange +1, and it makes it all the more scary that this got so many upvotes. – guillaume31 Feb 20 '18 at 13:35
  • Related: https://softwareengineering.stackexchange.com/questions/373284/what-is-the-use-of-dto-instead-of-entity – Dherik Jan 15 '19 at 11:20
  • As an opinion...your long term maintenance will be easier if you separate. "version1" you can get away with it most times. But when there comes deviations...your code starts getting hacked up when you mix concerns. I am so thankful I've adopted a "put it in early" mindset with this.... – granadaCoder Jul 29 '22 at 18:24

5 Answers5

31

It is up to you.

Most people will tell you that it's not a good practice but you can get away with it in some cases.

EF never played nicely with DDD for multiple reasons, but two stand out: you can't have parameterized constructors on your entities and you can't encapsulate collections. DDD relies on that, since the domain model should include both data and behavior.

In a way, EF forces you to have an anemic domain model and in this case you can use the entities as DTOs. You may run into some issues if you use navigation properties but you can serialize those entities and send them over the wire. It may not be practical though. You will have to control the serialization for each entity that has properties you don't need to send over. The easier way is to simply design separate classes tailored for data transfer. Libraries like AutoMapper are created for this purpose.

For example: Suppose you have a class called Person with the following definition:

public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; get; }

    // plus a bunch of other properties relevant about a person
}

Assuming you want to display a list of employees somewhere, it may be practical to send just the Id, FirstName and LastName. But you'll have to send over all the other irrelevant properties. It's not that big of an issue if you don't care about the size of the response but the general idea is to send just the relevant data. On the other hand, you might design an API that returns a list of persons and in that case sending all properties might be needed, thus making sense to serialize and send the entities. In this case, creating a DTO class is debatable. Some people like mixing up entities and DTOs, some people don't.

To answer your updated question, EF is an ORM. Its job is to map database records to objects and vice versa. What you do with those objects before and after passing through EF is not part of its concerns. Nor should it be.

devnull
  • 2,969
  • 20
  • 20
  • I think that there are ambiguous information since there are a lot of people who say that Data transfer object is to pass data between layers and the other hand it is to pass data between process. – user2484998 Jun 03 '17 at 08:30
  • DTOs are for sending data between processes. You may be thinking of POCOs, which are used for passing data between layers. They're not the same thing as DTOs. In your scenario, the EF entities are POCOs. – devnull Jun 03 '17 at 08:40
  • 1
    Briefly summarised. What are the differences between DTOs and POCOs? Don't they just hold data? – Laiv Jun 03 '17 at 11:27
  • Technically, they're both the same. Conceptually, POCOs may have behavior. – devnull Jun 03 '17 at 11:39
  • @devnull *"EF forces you to have an anemic domain model"* - this is completely wrong. You must be confusing anemic with persistence-aware. – guillaume31 Feb 20 '18 at 13:23
  • @guillaume31 I'd really love to see a solution where EF sets a customer's orders through the constructor or any other means except by making the orders collection writable. – devnull Feb 20 '18 at 14:42
  • What has this got to do with anemic? The tradeoff is not sacrificing rich domain object behavior, it's sacrificing persistence ignorance (oftentimes mitigated by putting narrow access modifiers on the collection - protected, and in EF Core you can even map private fields). – guillaume31 Feb 20 '18 at 14:55
  • 1
    @guillaume31 You can't have a true domain model without taking persistence into consideration. What good is a public interface if I'm forced to use reflection (not to mention other sorts of hacks, provided that my public property is backed by a private field named differently) for loading my aggregates in a valid state? If EF is not providing me with an infrastructure for hidrating my aggregates by using their public interface then I'm better off keeping my business logic elsewhere and have my domain anemic instead of writing additional boiler plate for loading them from the database. – devnull Feb 20 '18 at 15:22
  • 1
    So you'd rather make your entire domain model anemic than name your public collection getter the same way as the private field? (let's set the constructor problem aside, because it is most often against the domain in the first place to expose a constructor taking all of the object's fields...) – guillaume31 Feb 20 '18 at 15:39
  • @guillaume31 Given that my aggregate might have other dependencies than the data it's constructed from, yes, I'd rather have it anemic and spend my time on the actual business logic than on ways to go against the limitations. And I'm not saying that scalar properties can't/shouldn't be set directly, I'm strictly referring to collections. All this being said, the EF Core team might have softened up a bit to the outcry since 2.1 supports parameterized constructors. – devnull Feb 20 '18 at 15:59
  • I'm perfectly happy to live with the idea that a domain entity has one public interface and one hidden interface to rehydrate the object. If I feel that my data access tool skews the public interface too much, I switch to a separate data model/backing state object, while keeping an entity with rich behavior. – guillaume31 Feb 20 '18 at 16:05
  • @devnull It'd be good if you updated your answer to refer to EF Core too which supports parameterized constructors and hiding persistance specific data using private fields. – Konrad Jun 06 '18 at 09:00
  • @Konrad EF Core 2.1 support for parameterized constructors is very limited and doesn't accommodate the true DI we all think of. – devnull Jun 06 '18 at 10:00
  • @devnull any example of this limitation? – Konrad Jun 06 '18 at 10:19
  • 1
    @Konrad from [here](https://docs.microsoft.com/en-us/ef/core/modeling/constructors): `As of EF Core 2.1, only services known by EF Core can be injected. Support for injecting application services is being considered for a future release.` I very much like to have application services injected into my entities. – devnull Jun 06 '18 at 10:44
  • @devnull would you stop using DTOs if that would be supported? – Konrad Jun 06 '18 at 10:53
  • 1
    @Konrad I'd stop using my domain entities as DTOs (if I were to use them in this way). DTOs are useful regardless of EF's support for service injection. – devnull Jun 06 '18 at 11:00
  • As for the lack of parametrized constructors, that's not particularly EF refusing to play nicely. Parameterless constructors are required for **serialization**, and EF's translation from SQL result to entity is a form of serialization. – Flater Aug 10 '18 at 13:31
  • Hello everybody, junior here. So do I understand it correct? I it's good to create a common interface which I will use for my EF entity and JSON model, right? – Taras Kryvko Apr 05 '20 at 19:30
  • I am kind of stuck on this one because if I do not want to use my entities as DTO, in my opinion the entities should not be exposed, only to the code which handles EF (core) shizzle. But the problem is that my repository layer (or whatever returns data from the database) can only return DTO's since the entities cannot be exposed (because they are bound to EF) – Wilko van der Veen Dec 20 '21 at 14:31
12

No, it is not.

Ideally, DTOs will match your persistence repositories (aka, your database tables).

But your business classes are not necessarily a match. You might need additional classes , or separated, or joined classes to what you have in database. If your application is small, you might not really see this kind of problems, but in medium to large applications, this will happen often.

Another thing is that DTOs are part of the domain of whatever it is that deals with persistence, while your Business Layer should know nothing about them.

  • A [Command](https://martinfowler.com/bliki/CommandQuerySeparation.html) object is a DTO that the business layer should know something about. – devnull Jun 02 '17 at 19:55
  • I'm thinking the business layer will probably call the command object indirectly, through an interface. And I mean DTOs as in the simple objects that carry data, with no functionality at all. I am not sure if a command object is a DTO (https://martinfowler.com/eaaCatalog/dataTransferObject.html). – Juan Carlos Eduardo Romaina Ac Jun 02 '17 at 20:17
  • 1
    Usually, commands are separated into the actual command and its handler. The command contains the data, the handler contains the behavior. When used like this, the command part only contains data received from the client and acts as a DTO between the client and the business layer. – devnull Jun 02 '17 at 20:24
  • DTO don't flow from persistence to domain, they could also come from the outside as in comming data (think in REST APIs). As pointed by devnull, commands and events are somewhat DTOs and they are transfered to the business layer. If handlers are business layer or not depends on the design. – Laiv Jun 02 '17 at 21:18
9

No, it's a bad practice.

Some reasons:

  1. New entity fields will be in the Dto, by default. Use the entity means that every information will be available to be consumed by default. This can lead you to expose sensible informations or, at least, makes your API contract inflated, with a lot of informations that is not used for who consumes the API. Of course, you can ignore fields using some annotations (like @JsonIgnore from the Java world), but this leads to the next problem...
  2. Lots of annotations/conditions/controls on entity. You need to control what you would like to send on Dto, when some attribute name changed (this will break the contract), add some attribute that is not from the entity, the order of the attributes, etc. Soon you will see your simple entity with a lot of annotations, extra fields and each time will be harder to understand what's happening.
  3. Less flexibility. With a Dto you are free to break the information in more classes, change the attribute names, add new attributes, etc. You can't do this so easy with a entity as Dto.
  4. Not optimized. Your entity will be always bigger than a simple Dto. So you always will have more information to be ignored/serialized and probably more unnecessary information being transmitted.
  5. Lazy problems. Using the entity of some frameworks (like Hibernate), if you try to retrieve some information that was not lazy loaded inside a database transaction before, the ORM proxy will not be attached to the transaction and you will receive some kind of "lazy exception" just to call a get method of the entity.

So, it's easier and safe use some kind of mapper tool to help you on this job, mapping the entity fields to a Dto.

Dherik
  • 2,406
  • 20
  • 33
  • Everything is debatable here. (1) This can also be seen as an advantage; it's easily configurable with annotations. (2) That's lot's of annotations in an apart from that really dump data container without any logic. (3) Changing attribute names or adding attributes is easy for both entities and DTOs; just add or change the according annotation(-attributes). Advantage: Attributes can't be missed easily. (4) When receiving a DTO, all values need to be copied to an entity object; that can be much less efficient. (5) I don't understand what's different here when mixing DTOs and entities. – steffen Jun 15 '21 at 10:26
  • (I'm not saying I am pro merging DTO and entity classes.) – steffen Jun 15 '21 at 10:31
6

It is actually a very bad idea. Martin Fowler has an article about Local DTOs.

Long story short, DTO Pattern was used for transfering data outside the process, for example over the wire and not between layers inside the same process.

Constantin Galbenu
  • 3,242
  • 12
  • 16
  • As with all programming approaches, there's not one size fits all otherwise we'd not debate and discuss different patterns and approaches in every applciation we build, we'd just always use the same things. DTOs are essentially just POPOs they're just named to show some intent. There's nothing with using a DTO to "transfer data" between eg service, controller, and into view. There's nothing in the name or structure of the classes that indicate or limit from where and to data is transferred – James Oct 17 '19 at 08:34
1

To complete what @Dherik said, the main problems of using entity objects as data transfer objects are :

  1. In a transaction, you take the risk to commit changes made on your entity because you use it as a DTO (even if you can detach the entity of the session in a transaction, most of the time you'll need to check this state before any modification on your entity-DTO and assure that you are not in a transaction or that the session has been closed if you don't want the modifications to be persisted).

  2. The size of data you share between the client and the server: sometimes you don't want to send all the content of an entity to the client to minimize the size of the request's response. Separating the DTO from the entity is more flexible, so as to specialize the data that you want to send in certain use-cases.

  3. Visibility and maintenance : You have to manage your jpa/hibernate annotations on your entity's fields and maintain the jackson annotations to serialize in json at the same place (even if you can separate them from the entity implementation in putting them in the interface inherited by the entity). Then, if you change your DTO content in adding a new field, another person can probably think that it's a field of the entity, therefore a field of the table concerned in your database (even if you can use the @Transient annotation on all your DTO fields for the case ..!).

In my opinion, it creates noise when you read the entity, but my opinion is surely subjective.

BobDalgleish
  • 4,644
  • 5
  • 18
  • 23