hibernate – @ElementCollection – 奇怪的删除/插入行为
@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的所有关联logging,并重新插入所有以前的logging,加上新的logging。
我有这样的想法,位置上的equals / hashcode方法将解决问题,但它并没有改变任何东西。
任何提示都表示赞赏!
这个问题不知何故在JPA wikibook的ElementCollection
页面中解释过:
CollectionTable中的主键
JPA 2.0规范没有提供在
Embeddable
定义Id
的方法。 但是,要删除或更新ElementCollection
映射的ElementCollection
,通常需要一些唯一的键。 否则,在每次更新时,JPA提供者都需要从Entity
的CollectionTable
删除所有内容,然后再插入值。 因此,JPA提供者很可能会认为Embeddable
中的所有字段的组合是唯一的,并与外键(JoinColunm
(s))结合使用。 然而,这可能是低效率的,或者如果Embeddable
太大或太复杂,就不可行。
这正是(粗体部分)这里发生了什么(Hibernate不会为集合表生成主键,也无法检测到集合的哪个元素发生了变化,并会从表中删除旧内容以插入新内容)。
但是, 如果你定义了一个@OrderColumn
(指定一个用于维护列表的持久顺序的列 – 这在你使用List
是有意义的),Hibernate将创build一个主键 (由顺序列和连接列 ),并且能够在不删除整个内容的情况下更新集合表。
就像这样(如果你想使用默认的列名):
@Entity public class Person { ... @ElementCollection @CollectionTable(name = "PERSON_LOCATIONS", joinColumns = @JoinColumn(name = "PERSON_ID")) @OrderColumn private List<Location> locations; ... }
参考
- JPA 2.0规范
- 第11.1.12节“ElementCollection注释”
- 第11.1.39节“OrderColumn注解”
- JPA Wikibook
- Java Persistence / ElementCollection
除了帕斯卡尔的回答,你还必须至less设置一列为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中logging了这个需求:
HHH-7072等情况的解决方法。 如果集合元素是一个完全由可为空的属性组成的组件,那么我们现在必须强制重新创build整个集合。 有关更多信息,请参阅AbstractCollectionPersister构造函数中的hasNotNullableColumns的使用。 为了逐行删除,需要像“WHERE(COL =?OR(COL is null AND?is null))”这样的SQL,而不是当前的“WHERE COL =?” (对于大多数数据库,失败为空)。 请注意,参数必须绑定两次。 在我们最终将“参数绑定点”的概念添加到ORM 5+中的AST之前,处理这种types的条件要么非常困难,要么是不可能的。 强制娱乐并不理想,但在ORM 4中没有任何其他的select。
- 在Spring MVC中使用ScrollableResults-backed Stream作为返回types时遇到困难
- 何时在NHibernate / Hibernate OneToMany关系上使用inverse = false?
- JPA和Criteria API – 只select特定的列
- Spring Data-JPA与JPA:有什么区别?
- hibernate与JPA与JDO – 每个的利弊?
- 何时以及如何使用hibernate二级caching?
- Hibernate JPA,MySQL和TinyInt(1)用于Boolean而不是bit或char
- Spring Repository中是否可以使用原始SQL?
- Hibernate EnVers中的@NotAudited和RelationTargetAuditMode.NOT_AUDITED有什么区别?