Hibernate @OneToMany@JoinTable的休眠问题和更新操作

Hibernate @OneToMany@JoinTable的休眠问题和更新操作,hibernate,jpa,orm,hibernate-mapping,jointable,Hibernate,Jpa,Orm,Hibernate Mapping,Jointable,我遇到了一个有点奇怪的问题;我有以下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(

我遇到了一个有点奇怪的问题;我有以下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;
我正在做一个简单的测试:

  • 保留具有几个属性的位置
  • 更改其中一个属性的名称
  • 重新合并位置(使用更改的属性)
我的期望(考虑到传播)是,合并位置只会传播到属性,属性会得到更新。这种情况(广泛地)会发生-更改的属性的值确实会更新,但随后会在已存在映射的联接表中尝试新的插入。由于这种新的和不必要的插入,故障(如预期的)是:

原因:com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:键“PRIMARY”的重复条目“1-1”

现在,罪魁祸首似乎是
hashCode
equals
的实现方式-似乎当Hibernate持久化属性集时,集合持久化器会检查是否需要插入每个条目(每个属性):

if(collection.needsInserting(entry,i,elementType))

因此,由于其中一个属性的名称确实发生了更改,现在将其视为需要插入(这并不正确-不需要插入,只需要更新)-因此在联接表中执行插入操作。当然,我可以将id用于equals和hashcode,但这不是Hibernate推荐的方式,我也不希望这样做。 我是否在映射中遗漏了可能导致这种情况的内容?这是一个相当标准的映射-简单的一对多和简单的合并操作-有什么建议可以让它工作吗

感谢您的帮助

谢谢


欧根

第一点:在OneToMany中,您实际上不需要一个
可连接表
,因为子实体将保留一个多通关系回到父实体。我会把它拿出来

您可能缺少一些注释。在父类上,将
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;

然后,级联应该可以正常工作。

您正在调用哪个Hibernate方法来进行更新(
persist
merge
)?我正在调用merge(Spring Data JPA实际上正在调用merge)。删除了@JoinTable(映射为@manytomy时从后面遗留下来的);但是,我希望保持映射的单向性——首先是因为属性不知道位置(不同的JAR),其次是因为我不使用关系的另一个方向。与
mappedBy
相同-如果关系是单向的,则应为可选关系。或者你是说除非关系是双向的,否则我无法更新?谢谢你的回答。尤金,我同意你的看法。当你不设置双向关系时,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;