我遇到了一个有点奇怪的问题;我有以下JPA映射:
@Entity
public class Location {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "LOCATION_ID")
private Long id;
@OneToMany( cascade = { CascadeType.ALL }, fetch = FetchType.EAGER )
@JoinTable( joinColumns = { @JoinColumn( name = "LOCATION_ID" ) },
inverseJoinColumns = { @JoinColumn( name = "ATTRIBUTE_ID" ) } )
private Set<Attribute> attributes;
和:
@Entity
public class Attribute implements IAttributeSupport {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ATTRIBUTE_ID")
private Long id;
@Column(nullable = false) private String name;
@Column(nullable = false) private String value;
...
我正在做一个简单的测试:
我的期望(考虑传播)是合并位置只会传播到属性,这将更新。这种情况(广泛地)发生 - 更改的属性值确实已更新,但随后在连接表中尝试新的INSERT,其中映射已存在。由于这个新的和不必要的插入,失败(如预期)是:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '1-1' for key 'PRIMARY'
现在,罪魁祸首似乎是实现hashCode
和equals
的方式 - 看来,当Hibernate持久保存属性集时,集合持久性检查是否每个条目(每个属性) )需要插入:
if ( collection.needsInserting( entry, i, elementType ) )
所以,由于其中一个属性的名称确实发生了变化,现在这个被选中需要插入(这不是真的正确 - 不需要插入,只有更新) - 因此在Join中插入操作表。我当然可以使用id为equals和hashcode,但这不是Hibernate推荐的方式,而且我宁愿不这样做。 我在映射中遗漏了一些可能导致这种情况的内容吗?这是一个非常标准的映射 - 简单的一对多和简单的合并操作 - 任何使它工作的建议?
感谢任何帮助。
感谢。
尤金。
答案 0 :(得分:1)
第一点:在OneToMany中,您实际上并不需要JoinTable
,因为子实体会将ManyToOne关系保留回父级。我会把它拿出来。
您可能会遗漏几个注释。在父类上,将mappedBy
添加到@OneToMany
注释中,以指示子类的哪个成员与父项保持关联。在你的情况下,它可能是
@OneToMany(fetch = FetchType.EAGER, mappedBy = "location")
此外,有时Hibernate不能很好地使用标准的JPA级联注释(我正在处理同样的问题,并从直接的JPA转移到Hibernate级联注释)。完整补充将最终成为:
@Cascade(value = { org.hibernate.annotations.CascadeType.ALL,
org.hibernate.annotations.CascadeType.DELETE_ORPHAN })
@OneToMany(fetch = FetchType.EAGER, mappedBy = "location")
private Set<Attribute> attributes;
然后在孩子中,你需要有一个回到父母的参考:
@ManyToOne
@JoinColumn(name = "location_id")
private Location location;
然后级联应该正常工作。