0

我遇到了一个有点奇怪的问题;我有以下 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;
  ...

我正在做一个简单的测试:

  • 坚持一个具有一些属性的位置
  • 更改这些属性之一的名称
  • 将位置合并回来(使用更改后的属性)

我的期望(考虑到传播)是合并位置只会传播到属性,属性会得到更新。这种情况(广泛)发生 - 已更改的 Attribute 的值确实已更新,但随后在已存在映射的 Join Table 中尝试新的 INSERT。由于这个新的和不必要的插入,失败(如预期的那样)是:

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '1-1' for key 'PRIMARY'

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

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

因此,由于其中一个属性的名称确实发生了变化,现在这被认为需要插入(这并不正确 - 不需要插入,只需更新) - 因此在连接表中插入操作。我当然可以将 id 用于 equals 和 hashcode,但这不是 Hibernate 推荐的方式,我也不想这样做。我是否在映射中遗漏了可能导致此问题的某些内容?这是一个非常标准的映射 - 简单的一对多和简单的合并操作 - 有什么建议可以让它工作吗?

任何帮助表示赞赏。

谢谢。

欧根。

4

1 回答 1

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;

然后级联应该正常工作。

于 2012-07-18T13:16:54.153 回答