14

Is there a general method that can

 if(entity is persisted before){
     entity = entity.merge();
 }else{
     entity.persist();
 }

So the method contain above logic is safe everywhere?

Dreamer
  • 7,333
  • 24
  • 99
  • 179
  • 2
    Why do you need it? `merge()` already performs this check. – axtavt Apr 18 '13 at 20:09
  • @axtavt Thanks. So if the entity never persisted, then `merge()` will persist the entity? Otherwise merge the entity and return a merged copy? – Dreamer Apr 18 '13 at 20:13
  • 2
    Yes, but for transient object it returns persisted copy as well rather than persists original object. – axtavt Apr 18 '13 at 20:26

3 Answers3

19

If you need to know is object already in persistence context you should use contains method of EntityManager.

Only EntityManager can tell you is entity persisted or not, entity does not have such information.

Here you can check javadoc for contains method.

if (!em.contains(entity)) {
  em.persist(entity);
} else {
  em.merge(entity);
}
Miki
  • 7,052
  • 2
  • 29
  • 39
IgorMadjeric
  • 389
  • 2
  • 3
  • 1
    sure, this should be if (!em.contains(entity)) ? Otherwise, you are persisting an entity that is already "contained" within the em... – drone.ah Dec 03 '13 at 12:49
  • 2
    if the persisted entity is detached, this method will not work. – eastwater Oct 07 '17 at 03:30
  • 2
    As stated by @Sunnyday , this answer is misleading. Per JPA specification, the `contains(..)` method of `EntityManager` is not defined as a lookup method for the actual DB state of an `Entity`, but as a lookup within a persistence context. Further clarification is found in my answer here: https://stackoverflow.com/a/49114622/2849346 – MWiesner Mar 05 '18 at 16:15
4

To check if entity object has been persisted or not by the current PersistenceContext you can use the EntityManager method contains(Object entity)

stenix
  • 3,068
  • 2
  • 19
  • 30
Khalil
  • 259
  • 2
  • 8
2

Maybe it's too late, but here are my findings! If you have an entity with a generate value, you can use it to check if the entity is already in DB, assuming you are not modifying this value manually.

@Entity
public class MyEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Integer id;
   
    // getter...
}

public class Main {
    public static void main() {
        MyEntity myEntity1 = new MyEntity();
        MyEntity myEntity2 = em.find(MyEntity.class, 4);
        em.detach(myEntity2); // or em.close()

        // other stuff and modifications

        // begin transaction
        persistEntity(myEntity1); // will use persist()
        persistEntity(myEntity2); // will use merge()
        // commit transaction

    }

    // This will manage correctly entities in different state
    public void persistEntity(MyEtity entity) {
        if (myEntity.getId() != null) em.merge(entity);
        else em.persist(entity);
    }
}

Using em.contains(entity) will fail in this scenario:

public static void main(){
    MyEntity myEntity = em.find(MyEntity.class, 5);
    
    em.detach(myEntity); // or em.close()
  
    // We are going to execute persist() because the entity is detached
    if (!em.contains(myEntity)) 
        // This call will produce an exception org.hibernate.PersistentObjectException
        em.persist(myEntity);
    else 
        em.merge(myEntity);
}

There are a performance reasons to try to achieve what OP is trying to do. You surely can use em.merge() instead of em.persist(), but not without a cost.

A call to em.merge() is trying to retrieve an existing entity from DB with a SELECT query and update it. So if the entity was never persisted, this will waste some CPU cycles. On the other side em.persist() will only produce one INSERT query.

lifcik
  • 88
  • 1
  • 5