Home » Support » Forum » remove() and persist() in same transaction => Attempt to reuse an existing primary key value

remove() and persist() in same transaction => Attempt to reuse an existing primary key value

#1

Hello Support,

in our configuration (FlushModeType.AUTO) is the execution of  em.find(Entity.class, <id>) much faster than an equivalent query.

To optimize the Performance we define a special Entity (A) with additional data that use an existing ID of another Entity (B) from another class (another table). On this point we get no conflicts.

If we remove additional data for Entity (B) and then the special Entity (A) is empty, we remove the special Entity (A).

If we add additional data for Entity (B) we check if an Entity (A) with the ID of Entity (B) exist. If it exist we put the date to the existing otherwise we create it.

 

Now we got the problem that we try to do two thinks in the same transaction:

first remove additional Data -> The special Entity (with id 1) is empty and we remove() it.

then we add additional Data -> It not exist an special Entity (with id 1) theerfor we create and persit() it.

 

Then we get the following exception:

com.objectdb.o.UserException: Attempt to reuse an existing primary key value (Persist_Remove_Persist$EntityA:1)

 

We created a small test, to demonstrate our scenario:

import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.FlushModeType;
import javax.persistence.Id;
import javax.persistence.Persistence;

public final class Persist_Remove_Persist {

public static void main(String[] args) {

  EntityManagerFactory emf;
  emf = Persistence.createEntityManagerFactory("objectdb:$objectdb/db/test.tmp;drop");
  EntityManager em = emf.createEntityManager();
  em.setFlushMode(FlushModeType.AUTO);

  System.out.println("create and persist");
  em.getTransaction().begin();
  EntityA entity = new EntityA(1);
  em.persist(entity);
  em.getTransaction().commit();

  System.out.println("load and remove");
  em.getTransaction().begin();
  EntityA persitedEntity = em.find(EntityA.class, 1);
  em.remove(persitedEntity);

  // If we call a FLUSH it works.
  // em.flush();

  System.out.println("create and persist AGAIN");
  // create a new entity with the same id which was already removed!
  EntityA entityNew = new EntityA(1);
  em.persist(entityNew);
  em.getTransaction().commit();

  em.close();
  emf.close();
}

@Entity
public static class EntityA {
  public EntityA(int id) {
   this.id = id;
  }

  @Id
  int id;
}
}

A possible workaround, that this scenario works is to call a flush (see commet) after em.remove(entity);

But this is not efficient, as we are calling it potentially thousands of times.

 

Is it expected that the commands not executed in the order they are pushed to the context or is it a BUG?

#2

Your test case demonstrates a limitation of ObjectDB in removing an entity object and then in the same transaction persisting another object with the same primary key of the removed object.

Obviously a possible workaround is to update the object instead of removing and persisting it.

But we will check if we can release a quick patch to support this without the workaround.

ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
#3

ObjectDB version 2.7.0 fixes this issue. Thank you for the report.

ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
#4

Thank you for the fix. It works.


Post Reply

To post a reply and/or subscribe to update notifications - please login