Hibernate встраиваемое отображение списка с идентификатором

1

У меня есть объект Person с вложенным Адресом, и между ними существует отношение "один ко многим" (у человека может быть несколько адресов). Текущее отображение выглядит примерно так:

@Embeddable
public class Address {  
    // ... attributes
}

@Entity
public class Person {
    @ElementCollection(fetch = FetchType.EAGER)
    @JoinTable(name = "Person_addresses", joinColumns = @JoinColumn(name = "personid")
    )
    /*
    Attribute ovverrides with annotations
    */
    private java.util.Set<Address> addresses = new java.util.HashSet<Address>();    
}

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

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

Теги:
hibernate
jpa
annotations
hibernate-mapping

2 ответа

2
Лучший ответ

http://en.wikibooks.org/wiki/Java_Persistence/ElementCollection#Primary_keys_in_CollectionTable

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

Так вот, это невозможно.

2

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

Тем не менее, Hibernate имеет функцию non-spec, называемую "id bag", которая позволяет сопоставлять базовую или встраиваемую коллекцию с идентификатором для каждой строки, тем самым предоставляя вам эффективные обновления:

@Entity
public class Person {
    @CollectionId( columns={"address_id"}, type="int", generator="increment" )
    @ElementCollection(fetch = FetchType.EAGER)
    @JoinTable(name = "Person_addresses", joinColumns = @JoinColumn(name = "personid"))
    private java.util.List<Address> addresses = new java.util.ArrayList<Address>(); 
}

Однако обратите внимание на переключатель из Set to List. Также обратите внимание на сгенерированную структуру таблицы... выглядит очень много, как сущность;)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню