Является ли хорошей практикой использование объектов-сущностей в качестве объектов передачи данных?

29

Мне интересно, потому что, если это так, почему Entity Framework не предлагает логику для создания нового объекта с такими же свойствами для передачи данных между слоями?

Я использую объекты сущностей, которые я генерирую с помощью структуры сущностей.

user2484998
источник
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, не является частью его забот. И не должно быть.

devnull
источник
1
Кратко резюмируя. Каковы различия между DTO и POCO? Разве они не просто хранят данные?
Laiv
1
@ guillaume31 Вы не можете иметь истинную модель предметной области, не принимая во внимание настойчивость. Что хорошего в публичном интерфейсе, если я вынужден использовать отражение (не говоря уже о других видах хаков, при условии, что мое публичное свойство поддерживается частным полем с другим именем) для загрузки моих агрегатов в допустимом состоянии? Если EF не предоставляет мне инфраструктуру для скрытия моих агрегатов с помощью их открытого интерфейса, то мне лучше оставить свою бизнес-логику в другом месте и использовать мой домен анемично, вместо того, чтобы писать дополнительную схему для загрузки их из базы данных.
devnull
1
Таким образом, вы бы предпочли сделать вашу модель предметной области анемичной, чем назвать получателя публичной коллекции таким же образом, как частное поле? (давайте оставим проблему конструктора в стороне, потому что в первую очередь против домена выставляется конструктор, принимающий все поля объекта ...)
guillaume31
1
@ Конрад отсюда : 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
@ Конрад, я бы прекратил использовать свои доменные объекты в качестве DTO (если бы я использовал их таким образом). DTO полезны независимо от поддержки EF для внедрения сервисов.
devnull
8

Нет.

В идеале DTO будут соответствовать вашим постоянным репозиториям (или таблицам вашей базы данных).

Но ваши бизнес-классы не обязательно совпадают. Вам могут понадобиться дополнительные классы, или отдельные, или присоединенные классы к тому, что у вас есть в базе данных. Если ваше приложение маленькое, вы, возможно, не увидите такого рода проблем, но в средних и больших приложениях это будет происходить часто.

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

Хуан Карлос Эдуардо Ромайна Ас
источник
Объект Command - это DTO, о котором бизнес-уровень должен что-то знать.
devnull
Я думаю, что бизнес-уровень, вероятно, будет вызывать объект команды косвенно, через интерфейс. Я имею в виду DTO как простые объекты, которые переносят данные без какой-либо функциональности. Я не уверен, является ли объект команды DTO ( martinfowler.com/eaaCatalog/dataTransferObject.html ).
Хуан Карлос Эдуардо Ромайна Ac
1
Обычно команды разделяются на фактическую команду и ее обработчик. Команда содержит данные, обработчик - поведение. При таком использовании командная часть содержит только данные, полученные от клиента, и действует как DTO между клиентом и бизнес-уровнем.
devnull
DTO не перетекают из персистентности в домен, они также могут поступать извне, как при передаче данных (например, в REST API). Как указывает devnull, команды и события являются своего рода DTO и передаются на бизнес-уровень. Если обработчики бизнес-уровня или нет, зависит от дизайна.
Laiv
4

Это на самом деле очень плохая идея. У Мартина Фаулера есть статья о местных DTO .

Короче говоря, DTOPattern использовался для передачи данных вне процесса, например, по проводам, а не между слоями внутри одного и того же процесса.

Константин Гальбену
источник
Как и во всех подходах к программированию, не существует одного подходящего размера, в противном случае мы не будем обсуждать и обсуждать различные шаблоны и подходы в каждом приложении, которое мы создаем, мы просто всегда будем использовать одни и те же вещи. DTO - это, по сути, просто POPO, их просто называют, чтобы показать какое-то намерение. Нет ничего с использованием DTO для «передачи данных» между сервисом, контроллером и в поле зрения. В имени или структуре классов нет ничего, что указывало бы или ограничивало, откуда и в какие данные передаются
Джеймс
4

Нет, это плохая практика.

Несколько причин:

  1. Новые поля сущностей будут в Dto по умолчанию . Использование объекта означает, что каждая информация будет доступна для использования по умолчанию. Это может привести вас к раскрытию разумной информации или, по крайней мере, сделает ваш контракт API раздутым, с большим количеством информации, которая не используется для того, кто использует API. Конечно, вы можете игнорировать поля, используя некоторые аннотации (например, @JsonIgnoreиз мира Java), но это приводит к следующей проблеме ...
  2. Много аннотаций / условий / элементов управления на объекте . Вам нужно контролировать то, что вы хотите отправить на Dto, когда имя какого-либо атрибута изменилось (это нарушит контракт), добавить атрибут, который не принадлежит сущности, порядок атрибутов и т. Д. Вскоре вы увидите свой простой сущность с множеством аннотаций, лишними полями и каждый раз будет сложнее понять, что происходит.
  3. Меньше гибкости . С Dto вы можете разбить информацию на большее количество классов, изменить имена атрибутов, добавить новые атрибуты и т. Д. Вы не можете сделать это так легко с такой сущностью, как Dto.
  4. Не оптимизировано . Ваша сущность всегда будет больше, чем простая Dto. Таким образом, у вас всегда будет больше информации, которую нужно игнорировать / сериализовать, и, возможно, будет передаваться больше ненужной информации.
  5. Ленивые проблемы . Используя сущность некоторых фреймворков (например, Hibernate), если вы попытаетесь получить некоторую информацию, которая ранее не загружалась в транзакции базы данных, прокси-сервер ORM не будет присоединен к транзакции, и вы получите какое-то «ленивое исключение» просто чтобы вызвать getметод сущности.

Таким образом, проще и безопаснее использовать какой-либо инструмент картографирования, чтобы помочь вам в этой работе, сопоставляя поля сущностей с Dto.

Dherik
источник
1

Чтобы завершить то, что сказал @Dherik, основными проблемами использования объектов сущностей в качестве объектов передачи данных являются:

  1. В транзакции вы рискуете зафиксировать изменения, сделанные в вашей сущности, потому что вы используете ее в качестве DTO (даже если вы можете отсоединить сущность сеанса в транзакции, большую часть времени вам нужно будет проверить это состояние до того, как любые изменения в вашей сущности-DTO и убедитесь, что вы не участвуете в транзакции или что сеанс был закрыт, если вы не хотите, чтобы изменения были сохранены).

  2. Размер данных, которыми вы делитесь между клиентом и сервером: иногда вы не хотите отправлять все содержимое объекта клиенту, чтобы минимизировать размер ответа на запрос. Отделение DTO от объекта является более гибким, чтобы специализировать данные, которые вы хотите отправить в определенных случаях использования.

  3. Видимость и обслуживание. Вы должны управлять своими аннотациями jpa / hibernate на полях вашей сущности и поддерживать аннотации jackson для сериализации в json в одном месте (даже если вы можете отделить их от реализации сущности, поместив их в интерфейс, унаследованный организация). Затем, если вы измените свой контент DTO при добавлении нового поля, другой человек, вероятно, может подумать, что это поле сущности, следовательно, поле соответствующей таблицы в вашей базе данных (даже если вы можете использовать @Transientаннотацию для всех ваших полей DTO для дела ..!).

На мой взгляд, это создает шум, когда вы читаете сущность, но мое мнение, безусловно, субъективно.

Чарльз Вуйкар
источник