Hibernate – @ElementCollection – странное поведение удаления / вставки

@Entity public class Person { @ElementCollection @CollectionTable(name = "PERSON_LOCATIONS", joinColumns = @JoinColumn(name = "PERSON_ID")) private List locations; [...] } @Embeddable public class Location { [...] } 

Учитывая следующую структуру classов, когда я пытаюсь добавить новое место в список локаций Person, он всегда приводит к следующим SQL-запросам:

 DELETE FROM PERSON_LOCATIONS WHERE PERSON_ID = :idOfPerson 

А также

 A lotsa' inserts into the PERSON_LOCATIONS table 

Hibernate (3.5.x / JPA 2) удаляет все связанные записи для данного Person и повторно вставляет все предыдущие записи, а также новый.

У меня возникла идея, что метод equals / hashcode на Location решит проблему, но ничего не изменит.

Любые намеки приветствуются!

Проблема как-то объясняется на странице об ElementCollection JPA wikibook:

Первичные ключи в CollectionTable

Спецификация JPA 2.0 не дает возможности определить Id в Embeddable . Однако для удаления или обновления элемента отображения ElementCollection обычно требуется уникальный ключ. В противном случае при каждом обновлении провайдеру JPA необходимо будет удалить все из CollectionTable для Entity , а затем вставить значения обратно. Таким образом, поставщик JPA, скорее всего, предположит, что комбинация всех полей в Embeddable уникальна в сочетании с внешним ключом ( JoinColunm (s)). Однако это может быть неэффективным или просто невозможным, если Embeddable большая или сложная.

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

Однако, если вы определяете @OrderColumn (чтобы указать столбец, используемый для поддержания постоянного порядка списка, что имеет смысл с тех пор, как вы используете List ), Hibernate создаст первичный ключ (сделанный из столбца порядка и join ) и сможет обновить таблицу коллекций без удаления всего содержимого.

Что-то вроде этого (если вы хотите использовать имя столбца по умолчанию):

 @Entity public class Person { ... @ElementCollection @CollectionTable(name = "PERSON_LOCATIONS", joinColumns = @JoinColumn(name = "PERSON_ID")) @OrderColumn private List locations; ... } 

Рекомендации

  • Спецификация JPA 2.0
    • Раздел 11.1.12 «Аннотация элемента ElementCollection»
    • Раздел 11.1.39 «Кодовое обозначение заказа»
  • JPA Wikibook
    • Сохранение Java / ElementCollection

В дополнение к ответу Паскаля вы также должны установить по крайней мере один столбец как NOT NULL :

 @Embeddable public class Location { @Column(name = "path", nullable = false) private String path; @Column(name = "parent", nullable = false) private String parent; public Location() { } public Location(String path, String parent) { this.path = path; this.parent= parent; } public String getPath() { return path; } public String getParent() { return parent; } } 

Это требование описано в AbstractPersistentCollection :

Обходной путь для таких ситуаций, как HHH-7072. Если элемент коллекции является компонентом, который целиком состоит из свойств с нулевым значением, мы в настоящее время должны принудительно воссоздать всю коллекцию. Дополнительную информацию см. В использовании hasNotNullableColumns в конструкторе AbstractCollectionPersister. Чтобы удалить строку за строкой, для SQL потребуется «WHERE (COL =? OR (COL имеет значение null AND? Равно null))», а не текущий «WHERE COL =?» (сбой для null для большинства БД). Обратите внимание, что параметр должен быть связан дважды. До тех пор, пока мы в конце концов не добавим понятия «привязки параметров» к AST в ORM 5+, обработка этого типа условий является либо чрезвычайно сложной, либо невозможной. Форсирование restа не является идеальным, но на самом деле не имеет другого варианта в ORM 4.

  • LINQ To Entities не распознает метод Last. В самом деле?
  • В чем разница между @JoinColumn и mappedBy при использовании ассоциации JPA @OneToMany
  • Entity Framework слишком медленная. Какие у меня варианты?
  • Родные запросы JPA / Hibernate не распознают параметры
  • Классы classов Hibernate должны быть Serializable?
  • ORM для DELPHI win32
  • Django - id vs pk
  • .net ORM Сравнение
  • JPA CriteriaBuilder - Как использовать оператор сравнения «IN»
  • Вычисленное свойство с JPA / Hibernate
  • Каковы преимущества использования ORM?
  • Interesting Posts

    Преобразование разделенных запятыми элементов в столбцы

    Как я могу складывать / накладывать jPanels в Java?

    Как использовать Integer без знака в Java 8 и Java 9?

    Как отобразить вращающийся NSProgressIndicator в другом цвете?

    События мыши JLabel для перетаскивания

    Объем микрофона на максимальном, но слишком тихом

    Какой самый быстрый алгоритм сортировки связанного списка?

    Как сохранить Листовку в карте R в виде файла png или jpg?

    Как в codeys вызывать команду «at command» для модема gsm? Нестандартные send_sms и т. Д.

    Могу ли я создать виртуальную 3d-модель здания из двухмерных чертежей в формате PDF?

    Улучшение производительности объемной вставки в инфраструктуре Entity

    Хранение пользовательских объектов в NSMutableArray в NSUserDefaults

    Есть ли простой способ заполнения раскрывающегося списка в этой схеме базы данных доступа?

    Android: поддержка нескольких экранов

    Можно ли написать метод swap в Java?

    Давайте будем гением компьютера.