Does anyone have a good solution or workaround for this?

Shallow updates do not update foreign keys in the root object's associated database 
table.  By shallow, I mean that I have called setAutoStore(false) before the 
transaction.  Given our very complex object hierarchy, we are unable to use 
setAutoStore(true), which does a deep update.  This leads to a host of other issues 
such as reduced performance and optimistic lock collisions on objects which have not 
been modified.  We query for object sets and hang onto them long term, associating 
them with new and modified objects to be persisted.

I've been using two classes in my testing, Monster and Victim.  A Monster has a 
collection of Victims and a Victim knows his one Monster.  Test pseudocode follows:

1. Set auto store to false.
2. Create a new Monster in transaction A.
3. Create a new Victim in transaction B.
4. Set the victim's monster to the monster created in step 2.
5. Call update on the victim in transaction C.

Attributes on the victim are written out to the database except for the monsterId.

We're running the latest version of Castor, v0.9.4.1.

Following is the database schema, the code for the Monster, Victim, and Test, and 
Castor mappings

Thanks for any suggestions!

--- database schema ---
create table monster
 (id varchar(30),
  name varchar(30));

create table victim
 (id varchar(30),
  name varchar(30),
  monsterId varchar(30));

--- Monster ---
import java.util.Vector;

import org.exolab.castor.jdo.TimeStampable;

public class Monster implements TimeStampable {

    protected String id;
    protected String name;
    protected long timeStamp;
    protected Vector victims = new Vector();
    
    public String getId() {
        return id;
    }
    
    public void setId(String anId) {
        id = anId;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String aName) {
        name = aName;
    }
    
    public Victim createVictim() {
        return new Victim();
    }
    
    public Vector getVictims() {
        return victims;
    }
    
    public void addVictim(Victim aVictim) {
        victims.add(aVictim);
        aVictim.setMonster(this);
    }

    public void jdoSetTimeStamp( long aTimeStamp )
    {
        timeStamp = aTimeStamp;
    }

    public long jdoGetTimeStamp()
    {
        return timeStamp;
    }
}

--- Victim ---
import org.exolab.castor.jdo.TimeStampable;

public class Victim implements TimeStampable {

    private String id;
    private String name;
    private Monster monster;
    private long timeStamp;
    
    public String getId() {
        return id;
    }
    
    public void setId(String anId) {
        id = anId;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String aName) {
        name = aName;
    }
    
    public Monster getMonster() {
        return monster;
    }
    
    public void setMonster(Monster aMonster) {
        monster = aMonster;
    }

    public void jdoSetTimeStamp( long aTimeStamp )
    {
        timeStamp = aTimeStamp;
    }


    public long jdoGetTimeStamp()
    {
        return timeStamp;
    }
}

--- Monster mapping ---
<mapping>
  <class name="Monster" identity="id" key-generator="UUID">
    <description>The Monster</description>
    <cache-type type="count-limited" capacity="100"/>
    <map-to table="Monster" xml="Monster" />
    <field name="id" type="string" >
      <sql name="id" type="char"/>
      <xml name="id" node="attribute"/>
    </field>
    <field name="name" type="string" >
      <sql name="name" type="char"/>
      <xml name="name" node="attribute"/>
    </field>
    <field name="victims" type="Victim" required="true" collection="vector">
      <sql many-key="monsterId"/>
    </field>
  </class>
</mapping>

--- Victim mapping ---
<mapping>
  <class name="Victim" identity="id" key-generator="UUID">
    <description>A Victim</description>
    <cache-type type="count-limited" capacity="100"/>
    <map-to table="Victim" xml="Victim" />
    <field name="id" type="string" >
      <sql name="id" type="char"/>
      <xml name="id" node="attribute"/>
    </field>
    <field name="name" type="string" >
      <sql name="name" type="char"/>
      <xml name="name" node="attribute"/>
    </field>
    <field name="monster" type="Monster">
      <sql name="monsterId"/>
      <xml name="monsterId" node="attribute"/>
    </field>
  </class>
</mapping>

--- Test Code ---
import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;

import org.arch4j.persistence.ObjectQuery;
import org.arch4j.persistence.PersistenceManager;
import org.arch4j.persistence.PersistenceProvider;
import org.exolab.castor.jdo.ClassNotPersistenceCapableException;
import org.exolab.castor.jdo.Database;
import org.exolab.castor.jdo.DatabaseNotFoundException;
import org.exolab.castor.jdo.DuplicateIdentityException;
import org.exolab.castor.jdo.JDO;
import org.exolab.castor.jdo.OQLQuery;
import org.exolab.castor.jdo.PersistenceException;
import org.exolab.castor.jdo.QueryResults;
import org.exolab.castor.jdo.TransactionAbortedException;
import org.exolab.castor.jdo.TransactionNotInProgressException;

public class CastorTest {
    
    private Database db;
    
    public CastorTest() {
        
        try {
            JDO jdo = new JDO();
            jdo.setDatabaseName("project6");
            jdo.setConfiguration("./metadata/database.xml");
            jdo.setClassLoader(getClass().getClassLoader());
            db = jdo.getDatabase();
        }
        catch (DatabaseNotFoundException e) {
            System.out.println("* Database not found.");
            e.printStackTrace();
        }
        catch (PersistenceException e) {
            System.out.println("* Persistence exception while opening the database.");
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        CastorTest instance = new CastorTest();
        instance.testForeignKeyInShallowUpdate();
    }
    
    /**
     * Tests resolving foreign key references on shallow updates.
     */
    private void testForeignKeyInShallowUpdate() {
        
        System.out.println("--- testForeignKeyInShallowUpdate() ---");

        try {
            db.setAutoStore(false); // alert Castor to go shallow
            
            // create a monster
            Monster monster = new Monster();
            monster.setName("Tiamat");
            db.begin();
            db.create(monster);
            db.commit();
            
            // create a victim through Castor        
            Victim victim = new Victim();
            victim.setName("Victor");
            db.begin();
            db.create(victim);
            db.commit();
            
            victim.setMonster(monster);

            db.begin();
            db.update(victim); // does NOT write the monsterId to the Victim table
            db.commit();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}


____________________________________________________________________

Please look below this disclaimer for attachments.

This email and any files transmitted with it are confidential and 
intended solely for the use of the individual or entity to whom they 
are addressed. This communication may contain material protected by 
attorney-client privilege. If you are not the intended recipient or 
the person responsible for delivering the email to the intended 
recipient, be advised that you have received this email in error and 
that any use, dissemination, forwarding, printing, or copying of this 
email is strictly prohibited. If you have received this email in error
please notify the Information Systems Manager by telephone at (715)845-3111

[EMAIL PROTECTED]
http://www.wipfli.com

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

Reply via email to