Hi Louis-Frederic,

after thinking a bit on the problem i came to the conclusion that you
need to managed the updates yourself. I hacked in a short example that
should do the job but haven't tested it in any way. The main idea is
that you do not call db.update(object) but instead call
object.update(db) shown below. I hope the following code snippets are
enough to help you understand the idea behind it.


public abstract class AbstractPersistentObject {
    public void update(Database db) {
        db.update(this);
    }
}


import java.util.Iterator;
import java.util.List;

public class A extends AbstractPersistentObject {
    private Integer _identity;
    private String _simple;
    private List _bs;

    public Integer getIdentity() { return _identity; }
    public void setIdentity(Integer identity) { _identity = identity; }

    public String getSimple() { return _simple; }
    public void setSimple(String simple) { _simple = simple; }

    public List getBs() { return _bs; }
    public void setBs(List bs) { _bs = bs; }
    public void addB(B b) {
        if (b == null) return;
        if (!_bs.contains(b)) {
            _bs.add(b);
            b.addA(this);
        }
    }
    public void removeB(B b) {
        if (b == null) return;
        if (_bs.contains(b)) {
            _bs.remove(b);
            b.removeA(this);
        }
    }

    public void update(Database db) {
        // get new, unchanged A instance from db
        A newA = (A) db.load(A.class, this.getIdentity());

        // set all simple properties on new A instance
        newA.setSimple(this.getSimple());

        // remove all B's of n:m relation from new A instance
        Iterator newIter = newA.getBs().iterator();
        while (newIter.hasNext()) {
            newA.removeB((B) newIter.next());
        }

        // add all B's of this to new A instance after
        // reloading them from db.
        Iterator oldIter = this.getBs().iterator();
        while (oldIter.hasNext()) {
            B oldB = (B) oldIter.next();
            B newB = (B) db.load(B.class, oldB.getIdentity());
            newA.addB(newB);
        }

        // changes will be stored at commit of transaction
        // managed outside.
    }
}


import java.util.List;

public class B extends AbstractPersistentObject {
    private Integer _identity;
    private List _as;

    public Integer getIdentity() { return _identity; }
    public void setIdentity(Integer identity) { _identity = identity; }

    public List getAs() { return _as; }
    public void setAs(List bs) { _as = bs; }
    public void addA(A a) {
        if (a == null) return;
        if (!_as.contains(a)) {
            _as.add(a);
            a.addB(this);
        }
    }
    public void removeA(A a) {
        if (a == null) return;
        if (_as.contains(a)) {
            _as.remove(a);
            a.removeB(this);
        }
    }
}


Regards
Ralf


Louis-Frederic Huppé St-Hilaire schrieb:
> Hi Ralf,
> 
> First of all, thanks a lot for the quick, to-the-point answer.
> 
> I'll try and provide some specific information about our implementation to 
> see if it gives you any idea for a workaround.
> 
> Following are the mappings for 2 of our model objects in a many-to-many 
> relationship:
> 
> <class 
> name="com.castortech.iris.database.knowledgebase.modelobjects.Baserule" 
> identity="id" key-generator="IDENTITY">
>               <cache-type type="unlimited" />
>               <map-to xml="Baserule" table="Baserule" />
>               <field name="id">
>                       <sql name="id" />
>                       <bind-xml node="attribute" />
>               </field>
>               <field name="name">
>                       <sql name="name" />
>                       <bind-xml node="attribute" />
>               </field>
>               <field name="type">
>                       <sql name="type" />
>                       <bind-xml />
>               </field>
>               <field name="description">
>                       <sql name="description" />
>                       <bind-xml />
>               </field>
>               <field name="conditionQuery" 
> type="com.castortech.iris.database.knowledgebase.modelobjects.ConditionQuery">
>                       <sql name="conditionQuery" />
>                       <bind-xml />
>               </field>
>               <field name="severity">
>                       <sql name="severity" />
>                       <bind-xml />
>               </field>
>               <field name="helpText">
>                       <sql name="helpText" />
>                       <bind-xml />
>               </field>
>               <field name="quickFixList" 
> type="com.castortech.iris.database.knowledgebase.modelobjects.QuickFix" 
> collection="vector">
>                       <sql name="quickfix" many-table="baserule_quickfix" 
> many-key="baserule" />
>                       <bind-xml />
>               </field>
>               <field name="rulesetList" 
> type="com.castortech.iris.database.knowledgebase.modelobjects.Ruleset" 
> collection="vector">
>                       <sql name="ruleset" many-table="ruleset_baserule" 
> many-key="baserule" />
>                       <bind-xml />
>               </field>
>       </class>
> 
> <class 
> name="com.castortech.iris.database.knowledgebase.modelobjects.QuickFix" 
> identity="id" key-generator="IDENTITY">
>               <cache-type type="unlimited" />
>               <map-to xml="QuickFix" table="QuickFix" />
>               <field name="id">
>                       <sql name="id" />
>                       <bind-xml node="attribute" />
>               </field>
>               <field name="name">
>                       <sql name="name" />
>                       <bind-xml node="attribute" />
>               </field>
>               <field name="type">
>                       <sql name="type" />
>                       <bind-xml />
>               </field>
>               <field name="description">
>                       <sql name="description" />
>                       <bind-xml />
>               </field>
>               <field name="queryList" 
> type="com.castortech.iris.database.knowledgebase.modelobjects.QuickFixQuery" 
> collection="vector">
>                       <sql name="query" many-table="quickFix_query" 
> many-key="quickFix" />
>                       <bind-xml />
>               </field>
>               <field name="baseruleList" 
> type="com.castortech.iris.database.knowledgebase.modelobjects.Baserule" 
> collection="vector">
>                       <sql name="baserule" many-table="baserule_quickfix" 
> many-key="quickfix" />
>                       <bind-xml />
>               </field>
>       </class>
> 
> Baserule objects are shown to the user in a tree-like structure where 
> associated QuickFix objects are presented as children.  So we really need the 
> list of QuickFix objects to be present in each Baserule object.
> 
> When the user double-clicks on a given Baserule, a dialog appears allowing 
> for the editing of its name, description, etc.  The user must also be able to 
> associate (or disassociate) QuickFix objects to that Baserule.  That is where 
> we need a list of all QuickFix objects in the database, along with the list 
> of QuickFix objects already tied to the Baserule.
> 
> If the user does add associations, the subsequent call to update() on the 
> Baserule fails due to DuplicateIdentityExceptions being thrown.
> 
> I hope that my explanations are clear enough that you may think of a possible 
> workaround, because I am pretty much out of ideas.
> 
> Thanks again,
> LF
> 
> -----Original Message-----
> From: Ralf Joachim [mailto:[EMAIL PROTECTED] 
> Sent: Wednesday, October 05, 2005 6:22 PM
> To: [email protected]
> Subject: Re: [castor-user] Long transactions and many-to-many relationships 
> problem
> 
> Hi Louis-Frederic,
> 
> you are right that all objects are cached by castor as without this long 
> transactions would not work. What causes problems in your usecase is 
> that castor returns new copies of the cached objects for every transaction.
> 
> At the moment I have no idea how you can work around the problem or how 
> this can be resolved by castor.
> 
> If you could provide me with some more information
> - mapping of A and B
> - do you need list of B's on A
> - do you need list of A's on B
> I would try to find a work around.
> 
> Regards
> Ralf
> 
> 
> Louis-Frederic Huppé St-Hilaire schrieb:
> 
> 
>>Hi and here's my question:
>>
>>Let's say you have two model objects, A and B, in a many-to-many 
>>relationship. What you want to do is to let a user see and potentially 
>>edit all instances of A found in the database.
>>
>>This spells "long transaction" so you load all instances of A in a 
>>long transaction context and let the user edit them. In the dialog 
>>allowing for the edition of instances of A, a list of instances of B 
>>found in the database is shown so that the user can associate any of 
>>them to the currently edited instance of A. In order to retrieve that 
>>list, the database has to be queried in a new transaction.
>>
>>The problem is that the objects created in that second transaction are 
>>completely different than those created in the first part of the long 
>>transaction. Some of these objects happen to represent instances 
>>already represented by objects found under the currently edited 
>>instance of A. This translates into DuplicateIdentityExceptions being 
>>thrown when the update() method is called on the instance of A after 
>>new relations to instances of B have been added.
>>
>>Is there any way around that problem ? Is there any way, when loading 
>>the list of instances of B, to make JDO realize that some of the 
>>objects it is about to create already live in a cache somewhere which 
>>is associated to the current long transaction ? That cache has to 
>>exist since it is used for dirty checking according to the documentation.
>>
>>Otherwise, are we to understand that all objects that may potentially 
>>be involved in modifications in the context of a long transaction must 
>>be loaded all at once ? For simple scenarios, this is not too bad, but 
>>in the practical case I am facing, this would basically involve 
>>loading the whole database.
>>
>>Thanks in advance for the tips,
>>
>>LF
>>
> 
> 
> 
> -------------------------------------------------
> If you wish to unsubscribe from this list, please 
> send an empty message to the following address:
> 
> [EMAIL PROTECTED]
> -------------------------------------------------
> 
> 
> -------------------------------------------------
> If you wish to unsubscribe from this list, please 
> send an empty message to the following address:
> 
> [EMAIL PROTECTED]
> -------------------------------------------------

-- 

Syscon Ingenieurbüro für
Meß- und Datentechnik GmbH
Ralf Joachim
Raiffeisenstraße 11
D-72127 Kusterdingen
Germany

Tel.   +49 7071 3690 52
Mobil: +49 173 9630135
Fax    +49 7071 3690 98

Email: [EMAIL PROTECTED]
Web:   www.syscon-world.de

-------------------------------------------------
If you wish to unsubscribe from this list, please 
send an empty message to the following address:

[EMAIL PROTECTED]
-------------------------------------------------

Reply via email to