primary key conflict when cascade persisting new entities

198 Views Asked by At

Simplified version of my problem is this: I have three entities (annotations also simplified):

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

Now I need to persist these entities (to an empty DB). The entities are created as a result of parsing XML data, so it is not as simple as the following code, but in reality it is done like that (that is why I'm not reusing 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);

Now when I try to persist the newly created entity A via

entityManager.merge(a);

I get an exception

Unique index or primary key violation: "PRIMARY KEY ON PUBLIC.C(ID)"; SQL statement: 
INSERT INTO PUBLIC.C (ID, SOMEPROPERTY) VALUES (?, ?) ...

In the SQL log, I can see that OpenJPA (which is the provider I'm using) is trying to insert a row with id 31 to table C two times. However, I would expect that c1 and c2 objects are treated as equal, and just one row is inserted. How can I possibly achieve that?

0

There are 0 best solutions below