一尘不染

Hibernate-@ElementCollection-奇怪的删除/插入行为

hibernate

@Entity
public class Person {

    @ElementCollection
    @CollectionTable(name = "PERSON_LOCATIONS", joinColumns = @JoinColumn(name = "PERSON_ID"))
    private List<Location> locations;

    [...]

}

@Embeddable
public class Location {

    [...]

}

给定以下类结构,当我尝试将新位置添加到“人的位置”列表中时,它总是导致以下SQL查询:

DELETE FROM PERSON_LOCATIONS WHERE PERSON_ID = :idOfPerson

A lotsa' inserts into the PERSON_LOCATIONS table

Hibernate(3.5.x / JPA 2)删除给定Person的所有关联记录,然后重新插入所有以前的记录以及新的记录。

我有一个想法,即Location上的equals / hashcode方法可以解决此问题,但是它没有任何改变。

任何提示表示赞赏!


阅读 231

收藏
2020-06-20

共1个答案

一尘不染

在有关ElementCollectionJPA Wikibook 的页面中以某种方式解释了该问题:

CollectionTable中的主键

JPA 2.0规范不提供一种方式来定义IdEmbeddable但是,要删除或更新ElementCollection映射的元素,
通常需要一些唯一的键。否则,在每次更新的JPA的供应商将需要删除一切从
CollectionTableEntity,然后插入值回。
因此,JPA提供程序将最有可能假定中的所有字段的Embeddable组合与外键组合是唯一的JoinColunm。但是,这可能效率低下,或者如果Embeddable规模较大或过于复杂,那将是不可行的。

而这恰好是这里的内容(粗体部分)(Hibernate不会为集合表生成主键,也无法检测集合中 哪些元素 已更改,并且将删除表中的旧内容以插入新内容)。

但是, 如果 定义一个@OrderColumn(以指定用于维护列表的持久顺序的列-
由于使用List,这将很有意义),则Hibernate将创建一个 主键 (由 order列和join列组成
)并且能够在不删除全部内容的情况下更新收藏表。

这样的事情(如果您想使用默认的列名):

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

参考文献

2020-06-20