休眠双向多对多关联会创建重复项 [英] Hibernate Bi-Directional Many to Many association creates duplicates

查看:136
本文介绍了休眠双向多对多关联会创建重复项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题与这一个非常相似 Hibernate Bi-方向ManyToMany更新与二级缓存



我有类如下所示

  @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
@Entity
public class A {
private int id;
私人列表< 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;


$ b @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
@Entity
public class B {
private int id;
私人列表< 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 $ p
$ b

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

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

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

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

 从A_B中删除,其中b_id =? 

插入A_B(b_id,a_id)值(?,?)
插入A_B(b_id,a_id)值(?,?)

从A_B where a_id =?

插入A_B(a_id,b_id)值(?,?)
插入A_B(a_id,b_id)值(?,?)
插入A_B(a_id, b_id)值(?,?)
插入A_B(a_id,b_id)值(?,?)

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

解决方案

这是一个经典! p>

问题是你的映射都是所有者,当一个应该是所有者时,应该是相反的。因为两者都是所有者,所以对这两者的更改都会导致插入数据库;有一个所有者和一个逆向,只会有一组插入。



您应该可以重写 B :: getListA 为:

  @ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE},mappedBy =listB )
公共列表< A> getListA()

并且让所有的东西都有效。

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



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


My question is pretty similar to this one Hibernate Bi-Directional ManyToMany Updates with Second Level cache

I've class as shown below

@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);
     }
}

As expected in a Many to Many relation, I've been updating both sides of the bi-directional relation .

Now the problem I face is, duplicate entries popup when I try to add/update a item in the collection. The following is the code I use to persist the entity...

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

The following are the queries fired by Hibernate which are obtained from the logs.

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 (?, ?)

Where am I going wrong here ? How to get rid of the duplicates that are being inserted ? Cache is being flushed properly but the duplicate entries are the only problem !

解决方案

This is a classic!

The problem is that both of your mappings are owners, when one should be the owner, and one should be inverse. Because both are owners, changes to either will result in insertions to the database; with one owner and one inverse, there will only be one set of insertions.

You should be able to rewrite B::getListA as:

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

And have everything work.

Note that only the owning side as the @JoinTable annotation. As a rule, any given bit of the database is mapped in exactly one place in a JPA application. If you ever find yourself mapping something twice, take a long hard look to see if there's a better way to do it.

Incidentally, you don't need the targetEntity attributes; a JPA provider can work that out from the generics.

这篇关于休眠双向多对多关联会创建重复项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆