nih*_*t84 39 java orm hibernate jpa jpa-2.0
@Entity
public class Person {
@ElementCollection
@CollectionTable(name = "PERSON_LOCATIONS", joinColumns = @JoinColumn(name = "PERSON_ID"))
private List<Location> locations;
[...]
}
@Embeddable
public class Location {
[...]
}
Run Code Online (Sandbox Code Playgroud)
给定以下类结构,当我尝试将新位置添加到Person的位置列表时,它总是会导致以下SQL查询:
DELETE FROM PERSON_LOCATIONS WHERE PERSON_ID = :idOfPerson
Run Code Online (Sandbox Code Playgroud)
和
A lotsa' inserts into the PERSON_LOCATIONS table
Run Code Online (Sandbox Code Playgroud)
Hibernate(3.5.x/JPA 2)删除给定Person的所有相关记录,并重新插入所有以前的记录,再加上新记录.
我认为Location上的equals/hashcode方法可以解决问题,但它没有改变任何东西.
任何提示都表示赞赏!
Pas*_*ent 59
ElementCollection在JPA wikibook 的页面中以某种方式解释了该问题:
CollectionTable中的主键
JPA 2.0规范没有提供定义
Id中的方法Embeddable.但是,要删除或更新ElementCollection映射的元素, 通常需要一些唯一的密钥.否则,在每次更新时,JPA提供程序都需要从CollectionTablefor中删除所有内容Entity,然后重新插入值.因此,JPA提供商将最有可能假设所有的字段的组合Embeddable是独一无二的,结合外键(JoinColunm(S)).然而,这可能是低效的,或者如果Embeddable大或复杂则不可行.
这正是(粗体部分)这里发生的事情(Hibernate没有为集合表生成主键,也无法检测集合中的哪个元素发生了变化,并且会从表中删除旧内容以插入新内容).
但是,如果你定义一个@OrderColumn(指定一个用于维护列表的持久顺序的列 - 这在你使用a之后就有意义了List),Hibernate将创建一个主键(由order列和连接列组成)并且将能够更新集合表而不删除整个内容.
这样的东西(如果你想使用默认的列名):
@Entity
public class Person {
...
@ElementCollection
@CollectionTable(name = "PERSON_LOCATIONS", joinColumns = @JoinColumn(name = "PERSON_ID"))
@OrderColumn
private List<Location> locations;
...
}
Run Code Online (Sandbox Code Playgroud)
除了Pascal的答案之外,您还必须将至少一列设置为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;
}
}
Run Code Online (Sandbox Code Playgroud)
AbstractPersistentCollection中记录了此要求:
适用于HHH-7072等情况的解决方法.如果collection元素是一个完全由可空属性组成的组件,那么我们当前必须强制重新创建整个集合.有关详细信息,请参阅AbstractCollectionPersister构造函数中hasNotNullableColumns的使用.为了逐行删除,这需要像"WHERE(COL =?OR(COL是null和?是null))"这样的SQL,而不是当前的"WHERE COL =?" (对于大多数DB而言,无效为null).请注意,param必须绑定两次.在我们最终将"参数绑定点"概念添加到ORM 5+中的AST之前,处理这种类型的条件要么极其困难,要么不可能.强制娱乐并不理想,但在ORM 4中没有任何其他选择.