This one time, at band camp, Lincoln Spiteri said:

LS>Yes... But what if the object in the long transaction has been updated
LS>in between transactions. I have encountered this very same problem with
LS>a very complex object tree and long transactions. If this fix works then
LS>it will save the the hassle of having to delete objects that are deeply
LS>related and re-creating them. 
LS>
LS>The scenario I am dealing with is a statemachine type if thing with
LS>states and transitions, if I wish to add a state to a statemachine
LS>object loaded in from a different transaction (long transaction) I get
LS>allot of duplicates at the db layer. 
LS>
LS>Not good. Will try this out when I get a chance and report back.
LS>
LS>
LS>Lincoln
LS>
LS>-----Original Message-----
LS>From: Alexey A. Efimov [mailto:[EMAIL PROTECTED] 
LS>Sent: 19 June 2003 14:44
LS>To: [EMAIL PROTECTED]
LS>Subject: Re: [castor-dev] Fix for duplicate entry problem with long
LS>transactions andrelationships
LS>
LS>
LS>But I think that you must never you objects loaded in one transaction
LS>with objects in other transaction. My guess - you must reload class B in
LS>current transaction, then Castor will know about object B is already
LS>exists and call update. So, problem about you saying is problem of cross
LS>transactional mechanizm. 
LS>I guess needed method something like db.import(Object o) in Database
LS>interface. Method will be reload and mark as "in transaction" object.
LS>
LS>So if your transaction use some objects getted from external
LS>transactions you must declare imports: db.begin(); // TODO:
LS>db.import(b); b = (B)db.load(B.class, b.getId());
LS>
LS>A a = new A();
LS>a.setClassB(b)
LS>
LS>db.create(a);
LS>
LS>db.comit();
LS>
LS>All this needed becose you must be sure that object B - is valid object
LS>(you must realod it from database, before assigning into A), and second,
LS>you must lock this object in current transaction to prevent changing in
LS>diferect transaction while this transaction exists. This maybe in
LS>multithreading system.
LS>
LS>Maybe all this better do automatical (without invoking db.import), but I
LS>think it too hard to implement...
LS>
LS>Thanks!
LS>
LS>-----Original Message-----
LS>From: Frank Cobia [mailto:[EMAIL PROTECTED] 
LS>Sent: Thursday, June 19, 2003 1:31 AM
LS>To: [EMAIL PROTECTED]
LS>Subject: [castor-dev] Fix for duplicate entry problem with long
LS>transactions andrelationships
LS>
LS>
LS>I was having a problem today and I searched the archives and found
LS>several posts from people (including myself) with the same problem. Some
LS>of them from a year or more ago.
LS>
LS>The problem is as follows. You have two classes Class A and Class B.
LS>Class A has a 1-to-1 relationship to Class B (This may affect 1-to-N
LS>relationships also, I don't know). Create a new instance of Class A and
LS>call setClassB(), passing in an instance of Class B that was obtained
LS>from the database in a different transaction. Then call
LS>database.create() and pass the new Class A object as the argument. You
LS>will get a duplicate entry exception from the database, because JDO
LS>tries to insert the instance of Class B with a different primary key. I
LS>hop this explanation is understandable.
LS>
LS>I sat down and spent a few hours tracking down the cause of this problem
LS>and found it. If you look at the source code for
LS>org.exolab.castor.persist.ClassMolder in version 0.9.5 on line 1009
LS>there is the following code:
LS>
LS>tx.markCreate( fieldEngine, fieldClassMolder, o, null );
LS>
LS>Basically it blindly does an insert of any related objects that are not
LS>registered with the current transaction. The object of the relationship
LS>will never be registered with the transaction, because it was loaded
LS>from a different transaction.
LS>
LS>What should happen is that the object should be chaecked to see if it is
LS>TimeStampable and is still in the cache. If it was loaded in a different
LS>transaction and is still in the cache, then tx.markUpdate() should be
LS>called instead of tx.markCreate(). So, I changed the previously
LS>mentioned line to
LS>read:
LS>
LS>if ((fieldClassMolder._timeStampable == true) &&
LS>(((TimeStampable)o).jdoGetTimeStamp() > 0))
LS>    tx.markUpdate( fieldEngine, fieldClassMolder, o, null ); else
LS>    tx.markCreate( fieldEngine, fieldClassMolder, o, null );

All, 

I agree with both Alexey and Lincoln. Alexey's explanation that an object must
be loaded into the context of a transaction is definitely correct. But at the
same time, Lincoln is correct as well. 

Frank's fix will work with object's used in a long transaction because
those objects must be Timestampable. However, Alexey's explanation applies
to objects within short transactions because if the transaction context
is not aware of an object and it tries to create an object that already
exists causing the DuplicateIdentityException to be thrown.

I've added in Frank's fix to one of my working copies of CVS and it
appears to play nice. But before I commit this change to CVS, I need to
take a deeper look at it.

Bruce
-- 
perl -e 'print unpack("u30","<0G)[EMAIL PROTECTED]&5R\"F9E<G)E=\$\!F<FEI+F-O;0\`\`");'

----------------------------------------------------------- 
If you wish to unsubscribe from this mailing, send mail to
[EMAIL PROTECTED] with a subject of:
        unsubscribe castor-dev

Reply via email to