Skip to main content



      Home
Home » Eclipse Projects » EclipseLink » [resolved] Problem with Inserting/Updating in DescriptorEventListener callback methods
[resolved] Problem with Inserting/Updating in DescriptorEventListener callback methods [message #1096334] Wed, 28 August 2013 04:47 Go to next message
Eclipse UserFriend
Hi,

Would greatly appreciate a pointer in the right direction with the following issue:

  • I am registering a DescriptorEvent listener and receiving a preUpdate() callback when a UOW.commit() executes and my main object is saved
  • In the preUpdate() callback I would like to perform an insert, update or delete operations for some unrelated objects (mapped with EL, but not related to the main object) and I would like these inserts/updates to happen in the same transaction as the main save


I tried the following 3 methods without success. What's the proper way of doing this?

Following code is simplified for readability. Actual code sets the relevant properties of the LogRecord based on ev.getSource() object.

public void preUpdate(DescriptorEvent ev)
{
  UnitOfWork nestedUOW = ev.getSession().acquireUnitOfWork(); 
  LogRecord lr = (LogRecord) nestedUnitOfWork.registerNewObject(new LogRecord());
  lr.setTimeStamp(new Date());
  nestedUOW.commit();
}

No exception, but no insert happens

--------------------------
public void preUpdate(DescriptorEvent ev)
{
  UnitOfWork parentUOW = (UnitOfWork) ev.getSession(); 
  LogRecord lr = (LogRecord) parentUOW.registerNewObject(new LogRecord());
  lr.setTimeStamp(new Date());
}

No exception, but no insert happens

--------------------------
public void preUpdate(DescriptorEvent ev)
{
  LogRecord lr = new LogRecord();
  lr.setTimeStamp(new Date());
  InsertObjectQuery insertObjectQuery = new InsertObjectQuery(lr);
  ev.getSession().executeQuery(insertObjectQuery);
}


Exception telling me that I shouldn't be issuing direct queries via UOW
Exception Description: Objects cannot be written during a UnitOfWork, they must be registered.

[Updated on: Thu, 29 August 2013 00:38] by Moderator

Re: Problem with Inserting/Updating in DescriptorEventListener callback methods [message #1096648 is a reply to message #1096334] Wed, 28 August 2013 13:25 Go to previous messageGo to next message
Eclipse UserFriend
You 3rd method would be the most likely to work, but you should use the event preUpdateWithChanges() not preUpdate(), the preUpdate() event will be called on all registered objects, even if they do not have changes.
Re: Problem with Inserting/Updating in DescriptorEventListener callback methods [message #1096687 is a reply to message #1096648] Wed, 28 August 2013 14:26 Go to previous messageGo to next message
Eclipse UserFriend
James,

Thanks a lot for looking into this!

Third method indeed is what some samples that I found suggest I use, but it does not work, since the ev.getSession() is a UOW and it throws (Exception Description: Objects cannot be written during a UnitOfWork, they must be registered.) As far as I see it my options are limited to the following:

  • I can't use UOW registration mechanisms because at this point it's too late, EL is already in the process of calculating changes and my newly registered objects are ignored.
  • Issuing direct queries on the current UOW session would be ideal, I just need help figuring out how to bypass UOW validation that prevents it from happening
  • Obtaining a new independent session/UOW. This works, but I am a little uncomfortable since it commits LogRecords in a different transaction, so I may end-up with the LogRecord even if the main transaction rolls-back

I am using the preUpdate(), because sometimes none of the EL-tracked attributes in the main object are changed, but I still need to create a LogRecord

--
Tony






Re: Problem with Inserting/Updating in DescriptorEventListener callback methods [message #1096835 is a reply to message #1096334] Wed, 28 August 2013 19:26 Go to previous messageGo to next message
Eclipse UserFriend
Here is my attempt at solving this.

Main idea is to defer query execution until the time when UOW activates the commit manager and allows executeQuery calls to go through. UOW already has a very similar mechanism for deferring modifyAll queries, but nothing unfortunately that would allow deferring InsertObject or UpdateObject queries.

The following code organizes a storage for the deferred queries in the property of the parent UOW session (uow.getParent()) until the callback in the SessionEventAdapter.preCommitTransaction will allow me to execute the deferred queries. I had to use the parent UOW session instead of the UOW itself to store the queries because in the preCommitTransaction UOW session is no longer available

Any feedback would be greatly appreciated.

First, a helper class with 2 utility functions:

public class DBHelper
{

public static final String UOW_PROPERTY_DEFERRED_QUERY_SET = "DEFERRED_QUERY_SET";

public static void addDeferredDatabaseQuery(UnitOfWork uow, DatabaseQuery query)
{
  ArrayList<DatabaseQuery> deferredQueries = (ArrayList<DatabaseQuery>) uow.getParent().getProperty(UOW_PROPERTY_DEFERRED_QUERY_SET);
  if (deferredQueries == null)
  {
    deferredQueries = new ArrayList<DatabaseQuery>();
    uow.getParent().setProperty(DBHelper.UOW_PROPERTY_DEFERRED_QUERY_SET, deferredQueries);
  }
  uow.beginEarlyTransaction(); // I need this because that's the only way I found to force a transaction commit when EL did not track any changes in the main object
  deferredQueries.add(query);
}

public static void executeDeferredDatabaseQueries(Session  session)
{
   ArrayList<DatabaseQuery> deferredQueries = (ArrayList<DatabaseQuery>) session.getProperty(UOW_PROPERTY_DEFERRED_QUERY_SET);
   if (deferredQueries != null && !deferredQueries.isEmpty())
   {
     for (DatabaseQuery deferredQuery : deferredQueries)
     {
       session.executeQuery(deferredQuery);
     }
   }
}


public class SampleDescriptorListener extends DescriptorEventAdapter
{
  public void preUpdate(DescriptorEvent ev)
  {
    LogRecord lr = new LogRecord();
    lr.setTimeStamp(new Date());
    InsertObjectQuery insertObjectQuery = new InsertObjectQuery(lr);
    DBHelper.addDeferredDatabaseQuery((UnitOfWork)ev.getSession(), insertObjectQuery );
  }
}

public class SampleSessionListener extends SessionEventAdapter
{    
  public void preCommitTransaction(SessionEvent event)
  {
    DBHelper.executeDeferredDatabaseQueries(event.getSession());
  }
}

Re: Problem with Inserting/Updating in DescriptorEventListener callback methods [message #1096972 is a reply to message #1096334] Thu, 29 August 2013 00:38 Go to previous message
Eclipse UserFriend
Found a much easier solution with a lot less hacking:

public class ModifyAllQueryProxy extends ModifyAllQuery
{
    private DatabaseQuery actualQuery;

    public ModifyAllQueryProxy(DatabaseQuery actualQuery)
    {
        this.actualQuery= actualQuery;
        super.setShouldMaintainCache(false);
        super.setShouldDeferExecutionInUOW(true);
    }

    @Override
    public Object executeDatabaseQuery() throws DatabaseException, OptimisticLockException
    {
        return session.executeQuery(actualQuery);
    }
}


Now in the preUpdate everything looks clean:

public void preUpdate(DescriptorEvent ev)
{
  LogRecord lr = new LogRecord();
  lr.setTimeStamp(new Date());
  InsertObjectQuery insertObjectQuery = new InsertObjectQuery(lr);
  ev.getSession().executeQuery(new ModifyAllQueryProxy(insertObjectQuery));
}


UnitOfWork treatment of ModifyAllQueries is exactly what is needed here. Execution is deferred until UOW commit.
Previous Topic:Problem with JPA and User-defined type in Oracle
Next Topic:(Dead)lock in v2.4.2 with hsqldb and mysql
Goto Forum:
  


Current Time: Tue Jul 01 01:11:25 EDT 2025

Powered by FUDForum. Page generated in 0.10038 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top