【问题标题】:Hibernate Bi-Directional Many to Many association creates duplicatesHibernate Bi-Directional 多对多关联创建重复项
【发布时间】:2012-11-05 08:34:22
【问题描述】:

我的问题和Hibernate Bi-Directional ManyToMany Updates with Second Level cache这个问题很相似

我的课如下图所示

@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
@Entity 
public class A{
     private int id;
     private List<B> listB;

     ...
     @Cache (usage = CacheConcurrencyStrategy.TRANSACTIONAL)
     @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity = B.class)
     @JoinTable(name = "A_B", joinColumns = { @JoinColumn(name = "a_id") }, 
        inverseJoinColumns = { @JoinColumn(name = "b_id") })
     public List<B> getListB() {
         return listB ;
     }
}

@Cache (usage = CacheConcurrencyStrategy.TRANSACTIONAL)
@Entity
public class B{
     private int id;
     private List<A> listA;

     @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity = A.class)
     @JoinTable(name = "A_B", joinColumns = { @JoinColumn(name = "b_id") }, inverseJoinColumns = { @JoinColumn(name = "a_id") })
     public List<a> getListA() {
         return listA ;
     }

     public void addToA(A a) {
         a.getListB().add(this);
     }
}

正如在多对多关系中所预期的那样,我一直在更新双向关系的双方。

现在我面临的问题是,当我尝试添加/更新集合中的项目时会弹出重复的条目。以下是我用来持久化实体的代码...

b.getA().clear() ;
...
...
b.getListA().add(A) ;
b.addToA(A) ;
em.saveOrUpdate(b) ;

以下是从日志中获取的 Hibernate 触发的查询。

delete from A_B where b_id=?

insert into A_B (b_id, a_id) values (?, ?)
insert into A_B (b_id, a_id) values (?, ?)

delete from A_B where a_id=?

insert into A_B (a_id, b_id) values (?, ?)
insert into A_B (a_id, b_id) values (?, ?)
insert into A_B (a_id, b_id) values (?, ?)
insert into A_B (a_id, b_id) values (?, ?)

我哪里错了? 如何摆脱正在插入的重复项? 缓存被正确刷新,但重复的条目是唯一的问题!

【问题讨论】:

  • This answer 将帮助任何在读取而不是写入时看到重复的人。

标签: java hibernate caching


【解决方案1】:

这是经典!

问题是您的两个映射都是所有者,一个应该是所有者,一个应该是相反的。因为两者都是所有者,所以对其中任何一个的更改都会导致插入数据库;有一个所有者和一个逆,将只有一组插入。

您应该能够将B::getListA 重写为:

 @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, mappedBy = "listB")
 public List<A> getListA()

一切顺利。

注意只有拥有方作为@JoinTable注解。通常,数据库的任何给定位都映射到 JPA 应用程序中恰好一个的位置。如果您发现自己绘制了两次地图,请仔细查看是否有更好的方法。

顺便说一句,您不需要targetEntity 属性; JPA 提供者可以从泛型中解决这个问题。

【讨论】:

  • 太棒了!因此,使用 mappedBy 属性,我们通知 Hibernate 通知哪个是所有者表和实体的连接配置。我的理解正确吗?
  • 知道为什么在正确设置 mappedBy 后仍会收到重复插入吗?就我而言,我使用的是字段访问而不是方法访问​​。会不会是个问题?
  • 我一直在努力解决类似的问题。我的@OneToMany 实际上是一个单向(Order to Address)映射。最初,我使用 Set
    来收集订单的地址。问题是,每当将新的有效地址添加到集合中时,我都必须使旧地址的状态无效(这意味着更新现有地址并保留新的有效地址)。 Hibernate 正在向连接表中插入重复项。我已经尝试了我能找到的所有可能的解决方案。最后,将 Set
    更改为 List
    解决了所有问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-26
  • 1970-01-01
  • 2013-09-08
  • 2014-11-14
  • 1970-01-01
相关资源
最近更新 更多