Title: Transaction problem with referenced persistent objects
I have a follow-up to my earlier message. I found that my *problem* was that OrderStatus was defined in my mapping file as read-only. This makes perfect sense as I DO NOT wish to ever change these objects from my application. However, because they were read-only, they never got added to the collection of objects the transaction was aware of - so they were not considered persistable.
 
I suggest that the exception message produced by ClassMolder be modified to include the possibility that the object is not persistable as well as the current information about it coming from another transaction.
 
Further, I believe that this behavior is also counterintuitive along with the fact that I can't change the referenced field without having both objects opened in the same transaction. I don't expect the behavior to be changed, but it seems a little hokey to me.
 
Cheers!

Richard Porter
Software Engineer
Jel, Inc.

"Man is still the best computer...that can be mass produced with unskilled labor."
Werner Von Braun

-----Original Message-----
From: Richard Porter
Sent: Friday, June 06, 2003 11:22 AM
To: [EMAIL PROTECTED]
Subject: [castor-dev] Transaction problem with referenced persistent objects

I have a system using long transactions. In this system, I have a class representing an Order that references a class representing an OrderStatus. In the database, this is achieved with a foreign key relationship; in the Castor mapping, thusly:

        <field name="orderStatus" type="com.gene.apis.fulfillment.OrderStatus" required="true">
            <sql name="ORD_ORDERSTATUSID"/>
        </field>

I've created methods to retrieve, add, and update objects that are very self-contained. They begin a transaction, do their work, close the transaction, and return an object or collection of objects if the method is for a query. This means that when my client code wants to deal with an Order an change its status, it goes through the following steps:

1. Retrieve Order - this gives me an instance of the Order after having closed the transaction that retrieved it. I have a cache set up for Orders, so it can be updated later

2. Retrieve the correct instance of OrderStatus from the database to describe the new state - same as above in terms of the transaction which retrieves the OrderStatus being quickly closed; however, in this case I do NOT have a cache defined and never expect to update these objects (they are defined as read-only)

3. Set the orderStatus field on my Order with the newly retrieved OrderStatus

4. Call an update method to update the Order. It is included here in its entirety:
    public void updateOrder(Order pOrder) {
        Database db = getDB();
        try {
            db.begin();
            pOrder.setDateUpdated(new Date());
            pOrder.setUpdatedBy("FulfillmentManager.updateOrder");
            pOrder.setOrderStatus((OrderStatus)db.load(OrderStatus.class, new Long(pOrder.getOrderStatus().getId())));
            db.update(pOrder);
            db.commit();
        }
        catch (PersistenceException e) {
            StringBuffer msg = new StringBuffer(CONFIG.getString("error.update.order"));
            msg.append(pOrder.getId());
            LOGGER.error(msg.toString(), e);
            throw new RuntimeException(msg.toString() + " " + e.getMessage());
        }
        finally {
            CastorUtils.closeDb(db);
        }
    }

I'm getting the following exception:
org.exolab.castor.jdo.PersistenceException: Object, [EMAIL PROTECTED], links to another object, [EMAIL PROTECTED] that is not loaded/updated/created in this transaction

        at org.exolab.castor.persist.ClassMolder.preStore(ClassMolder.java:1290)
        at org.exolab.castor.persist.LockEngine.preStore(LockEngine.java:723)
        at org.exolab.castor.persist.TransactionContext.prepare(TransactionContext.java:1462)
        at org.exolab.castor.jdo.engine.DatabaseImpl.commit(DatabaseImpl.java:528)
        at com.gene.castor.fulfillment.FulfillmentManager.updateOrder(FulfillmentManager.java:179)
        at com.gene.apis.fulfillment.batchtrans.BatchManager.updateOrders(BatchManager.java:217)
        at com.gene.apis.fulfillment.batchtrans.BatchManager.retrieveConfirmationFile(BatchManager.java:183)
        at jsp_servlet._fulfillment._admin.__DELETEME._jspService(__DELETEME.java:93)
        at weblogic.servlet.jsp.JspBase.service(JspBase.java:27)
        at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:263)
        at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:302)
        at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:200)
        at weblogic.servlet.internal.WebAppServletContext.invokeServlet(WebAppServletContext.java:2390)
        at weblogic.servlet.internal.ServletRequestImpl.execute(ServletRequestImpl.java:1959)
        at weblogic.kernel.ExecuteThread.execute(ExecuteThread.java:137)
        at weblogic.kernel.ExecuteThread.run(ExecuteThread.java:120)

Now first of all, I consider it a small design flaw that Castor does not permit me to change the value of a referenced field that is neither dependent nor even writable. In reality, consider that all I'm doing is changing the value of a single long field on my ORDERS table. At worst, I'd expect to get an integrity constraint message from the underlying database on the rare cases where the object no longer existed.

My feelings on the behavior aside, in the code snippet above I am accounting for the behavior as it exists by re-retrieving the OrderStatus object from the database and setting the orderStatus field again, all within the same transaction scope. I had a similar problem earlier and this work-around resolved the issue. However in this case, I seem to be having no luck.

Am I doing something wrong here, is there another way of accomplishing what I want, or should I start diving through the ClassMolder to find either a bug or a new special case that hasn't been tested for yet?

I'm going to request that any answers to this question be mailed to me as well as posted to the development list, but will nonetheless monitor the list as well.

Cheers!
Richard Porter
Software Engineer
Jel, Inc.

"Man is still the best computer...that can be mass produced with unskilled labor."
Werner Von Braun

Reply via email to