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 решит проблему, но ничего не изменит.

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

2 Solutions collect form web for “Hibernate – @ElementCollection – странное поведение удаления / вставки”

Проблема как-то объясняется на странице об 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.

  • Выполнение вложений и обновлений с помощью Dapper
  • Я обнаружил, что JPA, или, похоже, не поощряет шаблон DAO
  • Какова лучшая страtagsя для модульных приложений, управляемых базами данных?
  • Должен ли я преобразовывать объекты Entity (Persistent) в объекты DTO?
  • В чем разница между однонаправленными и двунаправленными ассоциациями JPA и Hibernate?
  • Родные запросы JPA / Hibernate не распознают параметры
  • JPQL Создать новый объект в Select Statement - избегать или объявлять?
  • Автоматическое резервирование зарезервированного слова для таблиц и столбцов Hibernate
  • Hibernate, iBatis, Java EE или другой инструмент Java ORM
  • Сохранение карты с использованием JPA
  • В чем разница между JPA и Hibernate?
  • Interesting Posts

    Как использовать HTML для печати верхнего и нижнего колонтитула на каждой печатной странице документа?

    Надежная передача данных

    Как использовать относительные пути без включения имени корневого контекста?

    Замена всех не-буквенно-цифровых символов пустыми строками

    Лучший способ сравнить 2 XML-документа в Java

    НЕ используя шаблон репозитория, используйте ORM as is (EF)

    Автоматическое подключение к Интернету по умолчанию при запуске Windows

    Подключиться к главной машине с гостевой ОС VirtualBox?

    Остановка видео на YouTube

    Папки, названные в качестве текущего месяца по командной строке

    Некоторые веб-сайты отключают мою кнопку «назад», как я могу ее использовать?

    Как испортить компьютер под управлением Windows 7?

    Что происходит, когда гигабитные коммутаторы подключены через старый кабель CAT5?

    Как воспроизводить мелодию звонка / сигнала тревоги в Android

    Что такое команда sh?

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