JPA: Каково поведение слияния с отложенной инициализированной коллекцией? - PullRequest
7 голосов
/ 09 марта 2011

Вот последовательности, приводящие к вопросу:

  1. У меня есть запись команды и 3 записи игрока в базе данных. У сущности команды есть список, который использует FetchType.LAZY, CascadeType.ALL
  2. Нажата кнопка поиска в Интернете.
  3. Запрашивается запрос на стороне сервера с использованием JPA-запроса, при котором все записи команды обнаруживаются, в данном случае только 1 запись объекта команды, возвращенного из запроса (который имеет прокси из списка сущностей игрока)
  4. Сопоставьте этот teamEntity с DTO и верните это DTO в webui, пропустив отображение списка сущностей игроков
  5. Webui отображает DTO в html-форме, готовый к приему изменений от пользователя
  6. Пользователь изменяет свойства команды, например дату ее основания
  7. Нажата кнопка сохранения на веб-сайте
  8. Преобразование DTO в сущность команды, которая будет использоваться для обновления уже существующей записи команды
  9. Но в этом случае, если бы я использовал em.merge (teamEntity), командная запись будет обновлена, но что будет со списком игроков? Потому что при преобразовании из DTO в командную сущность teamEntity имеет пустой список игровых сущностей. И после слияния я заметил, что teamEntity имеет размер 0 деталей. Но после обновления этой сущности em.refresh (teamEntity) он вернет 3 размера детализации.

Я в замешательстве:

  1. Почему размер равен 0 после объединения? Это как не представлять запись больше
  2. Перед тестом я думал, что детали будут удалены, так как я объединяю teamEntity с пустой деталью.

Пожалуйста, просветите меня:)

Спасибо!

1 Ответ

10 голосов
/ 09 марта 2011

JPA Спецификация гласит:

Семантика операции слияние , примененной к объекту X, следующая:

  • Если X является отсоединенным объектом, состояние X копируется в ранее существующий экземпляр управляемого объекта X 'с таким же идентификатором или создается новая управляемая копия X' из X.

  • Если X является новым экземпляром объекта, создается новый экземпляр управляемого объекта X ', а состояние X копируется в новый экземпляр управляемого объекта X'.

  • Если X является удаленным экземпляром объекта, операция слияния создаст IllegalArgumentException (или фиксация транзакции завершится неудачей).

  • Если X является управляемым объектом, этооднако операция слияния игнорируется, но операция слияния каскадно объединяется с объектами, на которые ссылаются отношения из X, если эти отношения были аннотированы значением аннотации элемента cascade=MERGE или cascade=ALL.

  • Для всех объектов Y, на которые ссылаются отношенияиз X, имеющего значение элемента каскада cascade=MERGE или cascade=ALL, Y рекурсивно объединяется как Y '.Для всех таких Y, на которые ссылается X, X 'устанавливается на ссылку Y'.(Обратите внимание, что если X управляется, то X является тем же объектом, что и X '.)

  • Если X является объектом, объединенным с X', со ссылкой на другой объект Y, где cascade=MERGE или cascade=ALL не указано, тогда навигация той же ассоциации из X 'дает ссылку на управляемый объект Y' с таким же постоянным идентификатором, как Y.

Как видите, здесь нет магии.Состояние отдельного экземпляра копируется во вновь созданный управляемый экземпляр.Поскольку у вашего отсоединенного экземпляра есть пустой список, управляемый экземпляр также будет иметь его.

Дальнейшее поведение зависит от принадлежности отношения, поскольку представление в базе данных отражает сторону отношения с владельцем:

  • Если Team является владельцем, отношения между Team и Player s будут уничтожены во время сброса (но сам Player выживет, если у вас не будет orphanRemoval = true в ваших отношениях).
  • В противном случае наличие пустого списка в Team не повлияет на базу данных.

Если вы обновите Team до очистки контекста, все свойства Team будут перезаписаны значениями из базы данных, поэтому список Player s восстанавливается (поскольку пустой список игроков еще не был сброшен).

Если вы звоните flush() до вызова refresh(), а Team является стороной-владельцем, список будет пустым, поскольку уничтожение связей было передано в базу данных во время flush().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...