级联持久化新实体时的主键冲突

时间:2014-11-13 16:09:24

标签: jpa jpa-2.0 openjpa

我的问题的简化版本是:我有三个实体(注释也简化):

@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对象被视为相等,并且只插入一行。我怎么可能实现这个目标呢?

0 个答案:

没有答案