Использование сущностей вне транзакций не обязательно приводит к проблемам;у него могут быть действительные варианты использования.Тем не менее, есть довольно много переменных в игре, и как только вы выпустите их из поля зрения, вещи могут и пойдут на юг.Рассмотрим следующие сценарии:
- Ваша сущность не имеет никаких связей с другими сущностями, или эти связи довольно поверхностные и охотно извлекаются.Вы извлекаете эту сущность из хранилища, отсоединяете ее от модуля сохранения (неявно или явно) и передаете контроллеру.Контроллер не пытается изменить объект;он только сериализует его в JSON - полностью безопасно.
- То же, что и выше, но контроллер изменяет сущность перед сериализацией его в JSON - опять же, полностью безопасно (только не ожидайте, что эти изменения будут отражены в БД)
- То же, что и выше, но вы забыли отсоединить сущность от PU - ой, если контроллер изменяет сущность, вы можете либо увидеть ее отражение в БД, либо получить исключение закрытой транзакции;оба, скорее всего, непредвиденные последствия.
- То же, что и выше, но некоторые отношения сущности ленивы.Опять же, вы можете или не можете получить какие-либо исключения в зависимости от того, обращаются ли к этим ленивым свойствам или нет.
- И есть еще очень много комбинаций преднамеренного и непреднамеренного выбора дизайна ...
Как видите, вещи могут очень быстро выйти из-под контроля.Особенно, когда ваша модель должна развиваться: вскоре вы обнаружите, что возитесь с представлениями JSON, @JsonIgnore
, проекциями сущностей и так далее.Таким образом, эмпирическое правило: хотя может показаться заманчивым срезать некоторые углы и подвергать ваши объекты внешним слоям, это редко хорошая идея.Правильно спроектированное решение всегда имеет четкое разделение проблем между уровнями:
- Уровень персистентности никогда не предоставляет больше методов или объектов, чем требуется бизнес-логикой.Более того, одну и ту же таблицу (таблицы) можно и нужно отображать в несколько различных объектов в зависимости от случаев использования, в которых они участвуют.
- Уровень бизнес-логики (кстати, это ваш API, а не службы REST! См. Ниже)) никогда не вытекает какие-либо детали из персистентного слоя.Его методы четко определяют варианты использования из проблемной области.
- Уровень представления только переводит API, предоставленный бизнес-логикой, в ту или иную форму, подходящую для клиента, и никогда не реализует дополнительные варианты использования.Имейте в виду, что контроллеры REST, службы SOAP и т. Д. Логически являются частью уровня представления, а не бизнес-логики.
Так что да, краткий ответ таков: персистентные сущности не должны подвергаться воздействию внешних слоев.Одним из распространенных методов является использование DTO вместо этого;кроме того, объекты DTO предоставляют дополнительный уровень абстракции на случай, если вам нужно изменить свои сущности, но оставить API нетронутым или наоборот.Если в какой-то момент ваши DTO очень похожи на ваши сущности, существуют платформы отображения bean-компонентов Java, такие как Dozer, Orika, MapStruct, JMapper, ModelMapper и т. Д., Которые помогают устранить шаблонный код.
Попробуйте поискать «шестиугольную архитектуру»,Это очень интересная концепция для создания четко разделенных слоев.Вот одна из статей на эту тему https://blog.octo.com/en/hexagonal-architecture-three-principles-and-an-implementation-example/;, в которой используются примеры на C #, но они довольно просты.