Hibernate一对多关联可以保存重复项

时间:2014-02-15 20:30:55

标签: java hibernate jpa persistence

我有一个类A,可以与多个B(一对多)关联:

@Entity
@Table(name = "a")
public class A implements Serializable {

 private static final long serialVersionUID = 6796905221158242611L;

 @Id
 @GeneratedValue
 @Column(name = "a_id")
 private Long a_id;

 @Column(name = "name")
 private String name;

 @OneToMany(mappedBy = "a", cascade = CascadeType.ALL)
 private Set<B> bs;

 public void addB(B b) {
  if(bs == null)
   bs = new HashSet<B>();

  bs.add(b);
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }
}

和类B存储对A的引用:

@Entity
@Table(name = "b")
public class B implements Serializable {

 private static final long serialVersionUID = 6063558165223241323L;

 @Id
 @GeneratedValue
 @Column(name = "b_id")
 private Long b_id;

 @Column(name = "name")
 private String name;

 @ManyToOne(cascade = CascadeType.ALL)
 @JoinColumn(name = "a_id")
 private A a;

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public A getA() {
  return a;
 }

 public void setA(A a) {
  this.a = a;
 }
}

当我现在执行以下代码时,Hibernate将在表b中保存两个名称为b1的条目。我不知道如何避免这种情况或我做错了什么。

EntityManagerFactory emf = Persistence.createEntityManagerFactory(Configurations.MYSQL);
EntityManager em = emf.createEntityManager();

em.getTransaction().begin();

A a1 = new A();
a1.setName("a1");

A a2 = new A();
a2.setName("a2");

B b = new B();
b.setName("b1");

a1.addB(b);
a2.addB(b);

em.merge(a1);
em.merge(a2);

em.getTransaction().commit();

2 个答案:

答案 0 :(得分:1)

我认为你应该保存a1和a2而不是合并它们。从javadocs开始,这就是merge的作用。

  

使用。将给定对象的状态复制到持久对象上   相同的标识符如果当前没有持久化实例   与会话相关联,它将被加载。返回持久性   实例。如果给定实例未保存,请保存副本并返回   它作为一个新的持久化实例。给定的实例不会成为   与会话相关联。此操作级联到相关联   如果关联是使用cascade =“merge”映射的实例。

所以,既然你是级联合并你正在合并b。但是b未保存,因此将保存b的副本。因此合并a1将保存b的副本,合并a2将保存b的另一个副本。

答案 1 :(得分:0)

你可以通过在A和B之间创建一个映射表来实现这一点(它本身就有两个条目),因为每个B都存储一个列中对其A的引用,并且作为数据库的第一个正常形式状态,你只能具有原子值,因此没有单个B行在一列中具有A的两个主键。