Чи є хорошою практикою використання об'єктів сутності як об'єктів передачі даних?


29

Мені цікаво, тому що якщо так, то чому Entity Framework не пропонує логіки створити новий об'єкт із тими ж властивостями для передачі даних між шарами?

Я використовую об'єкти сутності, які генерую за допомогою сутності.


3
Я думаю, що це хороше питання, але я не можу сказати, тому що це важко читати, я не знаю, як це виправити. Відредагуйте своє запитання.
candied_orange

1
@CandiedOrange +1, і це стає ще страшніше, що за це було отримано стільки результатів.
guillaume31

Відповіді:


23

Тобі вирішувати.

Більшість людей скажуть вам, що це не є хорошою практикою, але ви можете піти з нею в деяких випадках.

EF ніколи не грає добре з DDD з кількох причин, але виділяються дві: ви не можете мати параметризовані конструктори для ваших організацій і не можете інкапсулювати колекції. DDD покладається на це, оскільки модель домену повинна включати як дані, так і поведінку.

Певним чином, EF змушує вас мати анемічну модель домену, і в цьому випадку ви можете використовувати сутності як DTO. Якщо ви користуєтесь навігаційними властивостями, ви можете зіткнутися з деякими проблемами, але ви можете серіалізувати ці об'єкти та надіслати їх по дроту. Це може бути не практично. Вам доведеться контролювати серіалізацію для кожної сутності, яка має властивості, які вам не потрібно надсилати. Найпростіший спосіб - просто спроектувати окремі класи, призначені для передачі даних. Для цього створені бібліотеки типу AutoMapper .

Наприклад: Припустимо, у вас є клас, викликаний Personіз таким визначенням:

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
}

Припускаючи , що ви хочете , щоб відобразити список співробітників де - то, може бути практичним , щоб відправити тільки Id, FirstNameі LastName. Але вам доведеться надіслати всі інші неактуальні властивості. Це не так вже й велике питання, якщо вам не байдуже розмір відповіді, але загальна ідея - надіслати лише відповідні дані. З іншого боку, ви можете розробити API, який повертає список осіб, і в цьому випадку може знадобитися надсилання всіх властивостей, таким чином має сенс серіалізувати та відправляти сутності. У цьому випадку створення класу DTO є дискусійним. Деяким подобається змішування об'єктів і DTO, деякі - ні.

Щоб відповісти на ваше оновлене запитання, EF є ORM. Його завдання полягає у зіставлянні записів бази даних на об’єкти та навпаки. Те, що ви робите з цими об'єктами до і після проходження через EF, не є частиною його занепокоєння. Не повинно бути.


1
Коротко резюмуємо. Які відмінності між DTO та POCO? Вони просто не зберігають дані?
Лаїв

1
@ guillaume31 Неможливо мати справжню модель домену, не враховуючи наполегливості. Яка користь є загальнодоступним інтерфейсом, якщо я змушений використовувати рефлексію (не кажучи про інші види хакерів, за умови, що моя публічна власність підтримується приватним полем, названим інакше) для завантаження агрегатів у дійсний стан? Якщо EF не надає мені інфраструктури для приховування моїх агрегатів за допомогою їх загальнодоступного інтерфейсу, то я краще зберігати свою ділову логіку в іншому місці та мати свій анемічний домен, а не писати додаткову табличку котла для завантаження їх із бази даних.
devnull

1
Отже, ви краще зробите всю модель домену анемічною, ніж називати свою публічну колекцію колекціонером так само, як приватне поле? (давайте відкладемо проблему конструктора, тому що найчастіше проти домену в першу чергу викрити конструктор, беручи всі поля об’єкта ...)
guillaume31

1
@Konrad звідси : 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.Я дуже люблю, щоб у мої організації були введені служби додатків.
devnull

1
@Konrad Я припинив би використовувати свої доменні об'єкти як DTO (якби я використовував їх таким чином). DTO корисні незалежно від підтримки EF для введення послуги.
devnull

8

Ні, це не так.

В ідеалі, DTO будуть відповідати вашим постійним сховищам (він же, таблиці вашої бази даних).

Але ваші бізнес-класи - це не обов'язково відповідність. Можливо, вам знадобляться додаткові класи, або відокремлені, або приєднані класи до того, що у вас є в базі даних. Якщо ваша програма невелика, ви, можливо, не відчуєте подібних проблем, але в середніх та великих програмах це трапляється часто.

Інша справа, що DTO є частиною домену будь-якого, що стосується наполегливості, тоді як ваш бізнес-шар не повинен нічого про них знати.


Command об'єкт є DTO , що бізнес шар повинен знати дещо - що о.
devnull

Я думаю, що бізнес-шар, ймовірно, буде викликати командний об'єкт опосередковано через інтерфейс. І я маю на увазі DTO, як у простих об'єктах, які несуть дані, без функціональності взагалі. Я не впевнений, чи командним об’єктом є DTO ( martinfowler.com/eaaCatalog/dataTransferObject.html ).
Хуан Карлос Едуардо Ромаїна Ак

1
Зазвичай команди розділяються на фактичну команду та її обробник. Команда містить дані, обробник містить поведінку. При такому використанні командна частина містить лише дані, отримані від клієнта, і діє як DTO між клієнтом і бізнес-рівнем.
devnull

DTO не переходить від постійності до домену, вони також можуть надходити ззовні, як при надходженні даних (подумайте в API REST). Як вказує devnull, команди та події є дещо DTO, і вони переносяться на бізнес-рівень. Якщо обробники ділового рівня чи ні, залежить від дизайну.
Лаїв

4

Це насправді дуже погана ідея. У Мартіна Фаулера є стаття про місцеві DTO .

Якщо коротко розповісти, DTOшаблон використовувався для передачі даних поза процесом, наприклад, по дроту, а не між шарами всередині того самого процесу.


Як і у всіх підходах до програмування, не один розмір підходить всім, інакше ми б не обговорювали та обговорювали різні шаблони та підходи у кожному створеному додатку, ми завжди завжди використовували одне і те ж. DTO по суті є лише POPO, вони просто названі, щоб показати певні наміри. Немає нічого з використання DTO для "передачі даних" між наприклад службою, контролером та переглядом. У назві чи структурі класів немає нічого, що вказує або обмежує, звідки і як передаються дані
Джеймс

4

Ні, це погана практика.

Деякі причини:

  1. Нові поля сутності за замовчуванням будуть у Dto . Використовувати сутність означає, що кожна інформація буде доступна для споживання за замовчуванням. Це може призвести до викриття розумної інформації або, щонайменше, зробить ваш контракт API завищеним, з великою кількістю інформації, яка не використовується тим, хто споживає API. Звичайно, ви можете ігнорувати поля, використовуючи деякі примітки (як, наприклад, @JsonIgnoreу світі Java), але це призводить до наступної проблеми ...
  2. Багато анотацій / умов / елементів управління суттю . Вам потрібно контролювати те, що ви хотіли б надіслати на Dto, коли якесь ім’я атрибута змінилося (це порушить контракт), додати якийсь атрибут, який не є сутністю, порядок атрибутів тощо. Незабаром ви побачите ваш простий сукупності з великою кількістю анотацій, додаткових полів і кожен раз буде складніше зрозуміти, що відбувається.
  3. Менша гнучкість . Завдяки Dto ви можете ламати інформацію в більшій кількості класів, змінювати імена атрибутів, додавати нові атрибути тощо. Ви не можете зробити це так легко з об'єктом, як Dto.
  4. Не оптимізовано . Ваша сутність завжди буде більшою, ніж простий Dto. Таким чином, у вас завжди буде більше інформації, яку потрібно ігнорувати / серіалізувати, і, ймовірно, більше зайвої інформації, що передається.
  5. Ледачі проблеми . Використовуючи сутність деяких фреймворків (наприклад, Hibernate), якщо ви спробуєте отримати деяку інформацію, яка раніше не ліниво завантажувалася всередині транзакції бази даних, проксі-сервер ORM не буде приєднаний до транзакції, і ви отримаєте якийсь "ледачий виняток" просто викликати getметод сутності.

Отже, простіше та безпечніше використовувати якийсь інструмент для картографування, який допоможе вам у цій роботі, зіставляючи поля об’єктів у Dto.


1

Для завершення того, що сказав @Dherik, основними проблемами використання об'єктів сутності як об'єктів передачі даних є:

  1. Під час транзакції ви ризикуєте здійснити зміни, внесені до вашої організації, оскільки ви використовуєте їх як DTO (навіть якщо ви можете від'єднати об'єкт сеансу в транзакції, більшу частину часу вам потрібно буде перевірити цей стан, перш ніж будь-які зміни у вашій сутності-DTO і запевняють, що ви не здійснюєте транзакцію або що сеанс був закритий, якщо ви не хочете, щоб зміни зберігалися).

  2. Розмір даних, якими ви обмінюєтесь між клієнтом та сервером: іноді ви не хочете надсилати клієнту весь вміст об'єкта, щоб мінімізувати розмір відповіді на запит. Відокремлення DTO від сутності є більш гнучким, щоб спеціалізувати дані, які ви хочете надіслати у певних випадках використання.

  3. Видимість та обслуговування: Ви повинні керувати своїми анотаціями jpa / hibernate на полях вашої особи та підтримувати анотації Джексона, щоб серіалізуватись у json на тому самому місці (навіть якщо ви можете відокремити їх від реалізації сутності, поставивши їх у інтерфейс, успадкований суб'єкт). Потім, якщо ви зміните вміст DTO, додаючи нове поле, інша людина, ймовірно, може подумати, що це поле сутності, тому поле відповідної таблиці у вашій базі даних (навіть якщо ви можете використовувати @Transientанотацію на всіх своїх полях DTO. для справи ..!).

На мою думку, він створює шум, коли читаєш сутність, але моя думка, безумовно, суб’єктивна.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.