2012-07-17 88 views
0

我遇到了一个有点奇怪的问题;我有以下的JPA映射:休眠问题@OneToMany @JoinTable和更新操作

@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'

现在,罪魁祸首似乎是hashCodeequals被implemneted的方式 - 它似乎是,当属性集获得由Hibernate持久化,留存检查集合,如果需要插入每个条目(每个属性):

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

所以,因为属性没有变化的一个名称,这是现在回升为需要被插入(即我s不是很正确 - 不需要插入,只需要更新) - 因此在连接表中插入操作。我当然可以使用id和hashcode,但这不是Hibernate推荐的方式,而且我宁愿不这样做。 我在映射中可能会导致这种情况吗?这是一个非常标准的映射 - 简单的一对多和简单的合并操作 - 任何建议,使其工作?

任何帮助表示赞赏。

谢谢。

Eugen。

+0

你正在调用哪个Hibernate方法来进行更新('persist'或'merge')? – atrain 2012-07-18 02:55:43

+0

我在调用合并(Spring Data JPA实际上是调用合并)。 – Eugen 2012-07-18 07:01:27

回答

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; 

级联应该正常工作。

+1

删除了@JoinTable(当映射为@ManyToMany时从后面留下);然而,我想保持映射单向 - 首先是因为属性不知道位置(不同的罐子),第二,因为我没有用于关系的另一个方向。 'mappedBy'相同 - 如果关系是单向的,那应该是可选的。或者你是否说我不能更新,除非关系是双向的?感谢你的回答。尤金。 – Eugen 2012-07-18 17:00:08

+1

我同意你的意见。当你不设置双向关系时,Hibernate很糟糕。休眠只是糟透了。这里是你的问题的错误报告:https://hibernate.onjira.com/browse/HHH-1268 ...不固定:( – redochka 2013-02-04 17:28:41