Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    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 08:47 Go to next message
Tony Oganesian is currently offline Tony OganesianFriend
Messages: 9
Registered: July 2009
Junior Member
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 04:38]

Report message to a moderator

Re: Problem with Inserting/Updating in DescriptorEventListener callback methods [message #1096648 is a reply to message #1096334] Wed, 28 August 2013 17:25 Go to previous messageGo to next message
James Sutherland is currently offline James SutherlandFriend
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

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.


James : Wiki : Book : Blog : Twitter
Re: Problem with Inserting/Updating in DescriptorEventListener callback methods [message #1096687 is a reply to message #1096648] Wed, 28 August 2013 18:26 Go to previous messageGo to next message
Tony Oganesian is currently offline Tony OganesianFriend
Messages: 9
Registered: July 2009
Junior Member
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 23:26 Go to previous messageGo to next message
Tony Oganesian is currently offline Tony OganesianFriend
Messages: 9
Registered: July 2009
Junior Member
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 04:38 Go to previous message
Tony Oganesian is currently offline Tony OganesianFriend
Messages: 9
Registered: July 2009
Junior Member
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: Sat Dec 20 18:01:55 GMT 2014

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

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