JPA объединяется в веб-приложение RESTful с DTO и оптимистичным блокированием?
Мой вопрос таков: Есть ли роль JPA merge
в веб-приложении без учета состояния?
В SO обсуждается операция merge
в JPA. Существует также отличная статья по этому вопросу, которая контрастирует слияние JPA с помощью более ручного процесса Do-It-Yourself (где вы находите объект через менеджер объектов и внесите изменения).
Мое приложение имеет богатую модель домена (проект, управляемый доменом ala), который использует аннотацию @Version
, чтобы использовать оптимистичную блокировку. Мы также создали DTO для отправки по проводам в рамках наших веб-сервисов RESTful. Создание этого слоя DTO также позволяет нам отправлять клиенту все, что ему нужно, и ничего не делает.
До сих пор я понимаю, что это довольно типичная архитектура. Мой вопрос о методах обслуживания, которым необходимо ОБНОВИТЬ (т.е. HTTP PUT) существующие объекты. В этом случае мы имеем следующие два подхода: 1) JPA Merge и 2) DIY.
Я не понимаю, как слияние JPA можно даже считать опцией для обработки обновлений. Здесь мое мышление, и мне интересно, есть ли что-то, чего я не понимаю:
1) Чтобы правильно создать отдельный объект JPA из проводного DTO, номер версии должен быть установлен правильно... else генерируется исключение OptimisticLockException. Но спецификация JPA говорит:
Сущность может получить доступ к состоянию своего поля версии или свойства или экспортируйте метод для использования приложением для доступа к версии, но не должны изменять значение версии [30]. Только поставщик постоянства разрешено устанавливать или обновлять значение атрибута версии в объект.
2) Слияние не обрабатывает двунаправленные отношения... поля обратной подсказки всегда заканчиваются как null.
3) Если какие-либо поля или данные отсутствуют в DTO (из-за частичного обновления), то слияние JPA удалит эти отношения или обнуляет эти поля. Hibernate может обрабатывать частичные обновления, но не слияние JPA. DIY может обрабатывать частичные обновления.
4). Первое, что будет использовать метод слияния, - это запросить базу данных для идентификатора объекта, так что для DIY не должно быть преимуществ по производительности.
5) В обновлении DYI мы загружаем объект и вносим изменения в соответствии с DTO - для этого нет вызова merge
или persist
, потому что контекст JPA реализует единицу, рабочий шаблон из коробки.
У меня есть это прямо?
Edit:
6) Поведение слияния в отношении ленивых загруженных отношений может отличаться среди поставщиков.
Ответы
Ответ 1
Использование Merge требует, чтобы вы отправляли и получали полное представление объекта или поддерживали состояние на стороне сервера. Для тривиальных операций типа CRUD-y это легко и удобно. Я использовал его много в веб-приложениях без состояния, где нет значимой угрозы безопасности, позволяя клиенту увидеть весь объект.
Однако, если вы уже сократили операции только для передачи непосредственно релевантной информации, вам также необходимо вручную создать соответствующие службы.
Просто помните, что при выполнении вашего "DIY" обновления вам все равно нужно передать номер версии на DTO и вручную сравнить его с тем, который выходит из базы данных. В противном случае вы не получите Оптимистическое блокирование, которое охватывает "пользовательское время" пользователя, которое у вас было бы, если бы вы использовали более простой подход слиянием.
-
Вы не можете изменить версию на сущности, созданной поставщиком, но когда вы сделали свой собственный экземпляр класса сущности с ключевым словом new
, это нормально и ожидается, что он установит на нем версию.
-
Это приведет к тому, что постоянное представление будет соответствовать представленному в памяти представлению, это может включать в себя создание нулевого значения. Помните, когда объект объединяется, этот объект должен быть отброшен и заменен на тот, который возвращается слиянием. Вы не должны объединять объект и продолжать его использовать. Его состояние не определяется спецификацией.
-
True.
-
Скорее всего, пока ваше решение DIY также использует идентификатор объекта, а не произвольный запрос. (Есть другие преимущества использования метода "найти" по запросу.)
-
True.
Ответ 2
Я бы добавил:
7) Merge переводит для вставки или обновления в зависимости от существования записи в БД, поэтому она не имеет отношения к оптимистическому обновлению vs-delete concurrency. То есть, если другой пользователь одновременно удаляет запись и вы ее обновляете, она должна (1) генерировать исключение concurrency... но это не так, оно просто вставляет запись как новую.
(1) По крайней мере, в большинстве случаев, на мой взгляд, это должно быть. Я могу представить некоторые случаи, когда я хотел бы, чтобы этот прецедент запускал новую вставку, но они далеки от обычного. По крайней мере, я бы хотел, чтобы разработчик дважды подумал об этом, а не просто согласился с тем, что "merge() == updateWithConcurrencyControl()", потому что это не так.