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]
-------------------------------------------------