1

I need a solution to update entity without select using EclipeLink 2.7. Here I found the following solution:

EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
UnitOfWork unitOfWork = ((EntityManagerImpl) entityManager.getDelegate()).getUnitOfWork();
AbstractSession session = unitOfWork.getParent();
session.updateObject(entity);
entityManager.getTransaction().commit();

And this is what I get:

Caused by: java.lang.ClassCastException: org.eclipse.persistence.internal.sessions.IsolatedClientSession cannot be cast to org.eclipse.persistence.internal.sessions.UnitOfWorkImpl
    at org.eclipse.persistence.internal.jpa.metadata.listeners.BeanValidationListener.preUpdate(BeanValidationListener.java:90) ~[org.eclipse.persistence.jpa.jar:na]
    at org.eclipse.persistence.descriptors.DescriptorEventManager.notifyListener(DescriptorEventManager.java:726) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.descriptors.DescriptorEventManager.notifyEJB30Listeners(DescriptorEventManager.java:696) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.descriptors.DescriptorEventManager.executeEvent(DescriptorEventManager.java:233) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.updateObjectForWrite(DatabaseQueryMechanism.java:901) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.queries.UpdateObjectQuery.executeCommit(UpdateObjectQuery.java:69) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.executeWrite(DatabaseQueryMechanism.java:259) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:60) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:911) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.internal.sessions.AbstractSession.internalExecuteQuery(AbstractSession.java:3346) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1892) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1874) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1824) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.internal.sessions.AbstractSession.updateObject(AbstractSession.java:4324) ~[org.eclipse.persistence.core.jar:na]

I tried to add to entity

@ExistenceChecking(ExistenceType.CHECK_CACHE)
public class MyEntity {...}

and

@ExistenceChecking(ExistenceType.ASSUME_EXISTENCE)
public class MyEntity {...}

however it didn't help. How to do update without select in EclipseLink 2.7?

Edit
I also tried

EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
UpdateObjectQuery updateQuery= new UpdateObjectQuery();
updateQuery.setObject(entity);
Session session = ((JpaEntityManager)entityManager.getDelegate()).getUnitOfWork().getParent();
session.executeQuery(updateQuery);
entityManager.getTransaction().commit();
entityManager.close();

But got :

Caused by: java.lang.ClassCastException: org.eclipse.persistence.internal.sessions.IsolatedClientSession cannot be cast to org.eclipse.persistence.internal.sessions.UnitOfWorkImpl
    at org.eclipse.persistence.internal.jpa.metadata.listeners.BeanValidationListener.preUpdate(BeanValidationListener.java:90) ~[org.eclipse.persistence.jpa.jar:na]
    at org.eclipse.persistence.descriptors.DescriptorEventManager.notifyListener(DescriptorEventManager.java:726) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.descriptors.DescriptorEventManager.notifyEJB30Listeners(DescriptorEventManager.java:696) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.descriptors.DescriptorEventManager.executeEvent(DescriptorEventManager.java:233) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.updateObjectForWrite(DatabaseQueryMechanism.java:901) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.queries.UpdateObjectQuery.executeCommit(UpdateObjectQuery.java:69) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.executeWrite(DatabaseQueryMechanism.java:259) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:60) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:911) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.internal.sessions.AbstractSession.internalExecuteQuery(AbstractSession.java:3346) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1892) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1874) ~[org.eclipse.persistence.core.jar:na]
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1824) ~[org.eclipse.persistence.core.jar:na]
Pavel_K
  • 10,748
  • 13
  • 73
  • 186
  • Looks like an issue with the BeanValidation class expecting a UnitofWork while the code executed is using the ClientSession parent instead. You are going to need to override the BeanValidation class to check if the session is a UOW first before trying to cast to it: https://github.com/eclipse/eclipselink.runtime/blob/master/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/listeners/BeanValidationListener.java or you will need to turn off validation to make this work. – Chris Apr 16 '18 at 17:13

2 Answers2

2

JPA merge is a specific API that requires providers pull an instance of your object from the cache or DB and then merge your instance's changes into it.

  UpdateObjectQuery updateQuery= new UpdateObjectQuery();
  updateQuery.setObject(myEntityInstance);
  Session session = ((JpaEntityManager)em.getDelegate()).getUnitOfWork().getParent();

  updated = (MyEntity)session.executeQuery(updateQuery);

instead of merge when I knew the object already exists and don't mind having all the fields included in the update statement. This allows me to use merge in other use cases when I have previously read this instance in this context already, or I need to make sure only updated fields are changed.

Chris
  • 20,138
  • 2
  • 29
  • 43
  • Thank you for your answer. But what should I do, if I want to update all fields of the object and context is closed. I just have an entity and I don't know what fields were changed, so I need to update all fields (except id). How to do it? – Pavel_K Apr 13 '18 at 18:32
  • sessionContext in my example was the instance I was updating - I've changed it in the answer to be 'myEntityInstance'. If your em context is closed, you need to get another one and then use the code above in a transaction to update your entity. – Chris Apr 13 '18 at 19:14
  • Seems I do something wrong. Could you take a look at edit in the question?. I would be very thankful for your help. – Pavel_K Apr 13 '18 at 19:32
1

@Chris pointed in comments that it is necessary to turn off bean validation. So I added to persistence.xml the following line

<property name="javax.persistence.validation.mode" value="none"/>

And the problem was solved.

Pavel_K
  • 10,748
  • 13
  • 73
  • 186