我的问题的简化版本是:我有三个实体(注释也简化):
@Entity
public class A
{
@Id
private int id;
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
private Collection<B> bs;
}
@Entity
public class B
{
@Id
private int id;
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
private Collection<C> cs;
}
@Entity
public class C
{
@Id
private short id;
private Object someProperty;
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj != null && getClass() == obj.getClass())
{
final C other = (C) obj;
return id == other.id;
}
return false;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = 31 + id;
return result;
}
}
现在我需要保留这些实体(到空数据库)。这些实体是作为解析XML数据的结果而创建的,所以它不像下面的代码那么简单,但实际上它是这样做的(这就是为什么我不重用c1):
A a = new A;
a.setId(1);
Collection<B> bs = new ArrayList<B>();
B b1 = new B();
b1.setId(21);
Collection<C> cs1 = new ArrayList<C>();
C c1 = new C();
c1.setId(31);
c1.setOtherProperty(null);
cs1.add(c1);
b1.setCs(cs1);
B b2 = new B();
b2.setId(22);
Collection<C> cs2 = new ArrayList<C>();
C c2 = new C();
c2.setId(31); // notice this is the same id as c1
c2.setOtherProperty(null);
cs2.add(c2);
b2.setCs(cs2);
bs.add(b1);
bs.add(b2);
a.setBs(bs);
现在,当我尝试通过
持久保存新创建的实体A.entityManager.merge(a);
我得到了一个例外
Unique index or primary key violation: "PRIMARY KEY ON PUBLIC.C(ID)"; SQL statement:
INSERT INTO PUBLIC.C (ID, SOMEPROPERTY) VALUES (?, ?) ...
在SQL日志中,我可以看到OpenJPA(我正在使用的提供程序)试图将一个id为31的行插入到表C中两次。但是,我希望c1和c2对象被视为相等,并且只插入一行。我怎么可能实现这个目标呢?