我有一个类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();
答案 0 :(得分:1)
我认为你应该保存a1和a2而不是合并它们。从javadocs开始,这就是merge的作用。
使用。将给定对象的状态复制到持久对象上 相同的标识符如果当前没有持久化实例 与会话相关联,它将被加载。返回持久性 实例。如果给定实例未保存,请保存副本并返回 它作为一个新的持久化实例。给定的实例不会成为 与会话相关联。此操作级联到相关联 如果关联是使用cascade =“merge”映射的实例。
所以,既然你是级联合并你正在合并b。但是b未保存,因此将保存b的副本。因此合并a1将保存b的副本,合并a2将保存b的另一个副本。
答案 1 :(得分:0)
你可以通过在A和B之间创建一个映射表来实现这一点(它本身就有两个条目),因为每个B都存储一个列中对其A的引用,并且作为数据库的第一个正常形式状态,你只能具有原子值,因此没有单个B行在一列中具有A的两个主键。