You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jdo-dev@db.apache.org by Craig L Russell <Cr...@Sun.COM> on 2005/11/29 01:09:46 UTC

Re: Questions on detach/attach and setDetachAllOnCommit

Hi Tony,

> Here are the questions:
>
> 1. Should the fetch-depth="0" defined in the class->field work?

Both the field-defined fetch-depth and the group1-defined fetch-depth  
are 0. So it's not clear what you mean.

> It does not have any effect right now in JPOX, but again, the spec  
> does not say anything about how this should work. I have to define  
> a fetch-group, so I can use the fetch-depth feature.

No, you can use fetch-depth on a field. And you do in your example.
<!ATTLIST field fetch-depth CDATA #IMPLIED>

  If you omit the fetch-group group1 from your example, the default  
fetch group should fetch the parent(s) recursively.

> What my assumption is "this is the default fetch-depth, which can  
> be overridden by field fetch-depth definition in individual  
> groups." Anyone have any idea?

Yes, the fetch-depth in the field definition can be overridden by the  
fetch-depth in individual groups.
>
> 2. When I save the first child, the parent and grandparent are also  
> saved. Since all 3 objects were transient before the makePersistent  
> call, they should be in detached state as the spec 13.4.2 said.

Right. First they are made persistent by reachability and then they  
are detached in place.

> Now I changed the parent's name to David, and call makePersistent  
> on child2 having the same parent. Is this legal?

It is not legal according to the Proposed Final Draft, but it is  
legal according to a change the expert group just approved. With the  
change, attachCopyAll no longer exists and you use makePersistentAll  
to attach objects or make transient objects persistent. So your usage  
is correct here.

> or should I call attachCopyAll instead? If it is legal, then what  
> should happen here? The spec has no definition what to expect to a  
> detached-dirty object referenced by the target object. Should JDO  
> save the parent's name?

Yes. Once JPOX code base has been updated to reflect the latest spec  
change, attaching a dirty-detached object will affect the cache, and  
the dirty object should be committed to the database as well as the  
newly created child2.
>
> 3. What should be the object referenced by the parent field of  
> child2 after the save?

When you called makePersistentAll on child2, it became persistent and  
a copy of its parent was put into the cache. And when you committed  
the transaction, the instances in the cache were detached. So the  
parent of child2 is a detached instance that has the new name and is  
distinct from the original parent.

> Note it is detach-all-on-commit. Should it be the original parent  
> instance, or a new detached-clean instance? If it is later case,  
> then the original detached parent instance become useless.

Well, it is still detached, it still has its version number and  
state, but it's now stale (it can't realistically be used further),  
and it's therefore not much use. If you are going to use instances  
after the commit, they should be from the instance graph that was  
most recently detached.

> Would not be better to have an attach method let the PM manage the  
> instance, so we can get it back after the transaction is committed,  
> using detach-all-on-commit or a detach method?

This scenario only works if the cache never contains instances with  
the same persistent object id as instances to be attached. And there  
are issues with rollback of detached instances that are attached in  
place.
>
> 4. What kind of instances should I got back from my listAll method?  
> detached-clean or hollow?

Regardless of whether the commented-out method is called, you will  
get detached instances. The effect of the commented-out method is  
that it creates a copy of the cached instances and detach-all-on- 
commit doesn't create a copy but detaches in place.

> According to my understanding of detach-all-on-commit, they should  
> be detached-clean, am I right? Do I need to call detachCopyAll to  
> get the detached instances?

There is no need to call detachCopyAll for this case.
>
> Thank you for your help in advance!

You are welcome in arrears.

Craig
>
> Tony
On Nov 28, 2005, at 6:52 AM, Tony Lai wrote:

> Hi,
>
> Since these questions are about the spec, I hope someone from the  
> expert group can give me the answers.  This is also posted on  
> JDOCentral's forums http://www.jdocentral.com/forums/index.php? 
> s=37b48c123ee46e821f97901d00afaeeb&showtopic=1590.
>
> First, let me define a couple simple classes for demo purpose.
> CODE
> public class Person implements DetachCallback {
>    private String name;
>    private Person parent;
>
>    public Person(String name) {
>        this(name, null);
>    }
>    public Person(String name, Person parent) {
>        this.name = name;
>        this.parent = parent;
>    }
>    ...getters and setters...
>
>    public String toString() {
>        String parentStr = null;
>        try {
>            Person myParent = getParent();
>            if(myParent != null) {
>                parentStr = myParent.toString();
>            }
>        } catch(Exception x) {
>            //may be caused by field not loaded.  Ignore it for now
>        }
>        return name +"["+System.identityHashCode(this)+"]"+
>            (parentStr == null ? "" : (" parent: " + parentStr));
>    }
>
>    public void jdoPreDetach() {}
>    public void jdoPostDetach(Object detached) {
>        System.out.println("jdoPostDetach: "+name);
>    }
> }
>
> public class DetachTest {
>    protected PersistenceManager pm;
>
>    Person grandParent = new Person("Bob");
>    Person parent = new Person("Dave", grandParent);
>    Person child1 = new Person("John", parent);
>    Person child2 = new Person("Mary", parent);
>
>    public DetachTest () {
>        pm = createPersistenceManager();
>        pm.setDetachAllOnCommit(true);
>    }
>
>    public void test() {
>        //This should save child1, parent, and grandParent.
>        makePersistent(child1);
>        System.out.println(child1);
>
>        // Now change the parent name
>        parent.setName("David");
>        makePersistent(child2);
>        System.out.println(child2);
>
>        System.out.println();
>        List list = listAll(Person.class, true, "group1");
>
>        for (Iterator i = list.iterator(); i.hasNext();) {
>            Object obj1 = i.next();
>            System.out.println("    item: "+obj1);
>        }
>     }
>
>    public static void main(String[] args) {
>        new DetachTest ().test();
>    }
>
>    public void makePersistent(Object obj) {
>        Transaction tx = pm.currentTransaction();
>        try {
>            tx.begin();
>            pm.makePersistent(obj);
>            tx.commit();
>        } finally  {
>            rollbackIfActive(tx);
>        }
>    }
>
>    public List listAll(Class targetClass, String fetchGroup) {
>        Transaction tx = pm.currentTransaction();
>        Extent extent = null;
>        try {
>            tx.begin();
>            pm.getFetchPlan().setGroup(fetchGroup);
>
>            List data = new ArrayList();
>            extent = pm.getExtent(targetClass,false);
>
>            for (Iterator i = extent.iterator(); i.hasNext();) {
>             Object obj1 = i.next();
>             data.add(obj1);
>            }
>            //data = (List)pm.detachCopyAll(data);  // see question 4
>
>            tx.commit();
>            return data;
>        }  finally {
>            closeIterators(extent);
>            rollbackIfActive(tx);
>        }
>    }
>    ... some helper methods...
> }
>
> <jdo>
>   <package name="test.jpox.detach">
>      <class name="Person" detachable="true">
>         <field name="parent" default-fetch-group="true" fetch- 
> depth="0"/>
>         <fetch-group name="group1">
>          <fetch-group name="default"/>
>            <field name="parent" fetch-depth="0"/>
>         </fetch-group>
>      </class>
> </package>
> </jdo>
>
>

Craig Russell
Architect, Sun Java Enterprise System http://java.sun.com/products/jdo
408 276-5638 mailto:Craig.Russell@sun.com
P.S. A good JDO? O, Gasp!


Re: Questions on detach/attach and setDetachAllOnCommit

Posted by Andy Jefferson <an...@jpox.org>.
Hi Tony,

> I only define the fetch-group "group1" because the fetch-depth defined in 
> the class field does not work, and JPOX developers (Andy in this case) is 
> not clear what the expectation is since it is not defined in the spec.  Can 
> you add a little clearification to the spec on this issue, please?

I'm actually well aware of what has been discussed in the EG. I simply have no 
plans on implementing a new definition of a feature in JPOX until I have a 
spec in front of me that defines it. JPOX has implemented many things in the 
past that have featured in specs and then have changed. We have plenty of 
other things to work on to not be implementing changes that have no written 
definition yet.

When Craig provides the next spec with the discussed definition of fetch-depth 
it will be implemented by us.

-- 
Andy

Re: Questions on detach/attach and setDetachAllOnCommit

Posted by Tony Lai <tl...@leversoft.com>.
Hi Graig,

Thank you for your answers.  Let me clearify a little thing here.  I only define the fetch-group "group1" because the fetch-depth defined in the class field does not work, and JPOX developers (Andy in this case) is not clear what the expectation is since it is not defined in the spec.  Can you add a little clearification to the spec on this issue, please?

I still have a few questions on your statement:
  Well, it is still detached, it still has its version number and state, but it's now stale (it can't realistically be used further), and it's therefore not much use. If you are going to use instances after the commit, they should be from the instance graph that was most recently detached.
Not just the original parent instance become useless, but also the child1 since it is pointing to that parent.  Therefore if I want to have a valid child1 after child2 is saved, I need to include child1 as part of the makePersistentAll call, and then re-assign child1 to the new copy.
  This scenario only works if the cache never contains instances with the same persistent object id as instances to be attached. And there are issues with rollback of detached instances that are attached in place.
Wouldn't that be a bigger problem if you attachCopy an object to a PM containing an instance with the same persistent object id in its cache already?  For example.  After the first makePersistent call to child1, I can:
  tx.begin();
  pm.makePersistent(child2);
  pm.attachCopy(child1);
  tx.commit();
Should I get an exception on my attachCopy(child1) call because I am attaching the parent that is already in the cache?  But I am not attaching the parent.  It just happen to be referenced by both children.  If the parent is attached (not a copy) to the cache, at least we know the parent is attached already, and there is no need to attach it again in the secode call.  I know I can call makePersistentAll(new Object[]{child1, child2}).  I just want to make my point that attaching the original object should not create additional problems.  Rollback a detached instance should be easier too, so I believe.  Just make a copy before the attach, and restore the content in a rollback.

I understand there are cases that attaching a copy is required, but attaching the original may reduce some unnecessary code.  Why don't you provide both, and let the developers choose which one to use?

Regards,
Tony
----- Original Message ----- 
  From: Craig L Russell 
  To: Tony Lai ; Apache JDO project ; JDO Expert Group 
  Sent: Monday, November 28, 2005 7:09 PM
  Subject: Re: Questions on detach/attach and setDetachAllOnCommit


  Hi Tony,


    Here are the questions:

    1. Should the fetch-depth="0" defined in the class->field work? 



  Both the field-defined fetch-depth and the group1-defined fetch-depth are 0. So it's not clear what you mean.


    It does not have any effect right now in JPOX, but again, the spec does not say anything about how this should work. I have to define a fetch-group, so I can use the fetch-depth feature. 



  No, you can use fetch-depth on a field. And you do in your example.
  <!ATTLIST field fetch-depth CDATA #IMPLIED>


   If you omit the fetch-group group1 from your example, the default fetch group should fetch the parent(s) recursively.


    What my assumption is "this is the default fetch-depth, which can be overridden by field fetch-depth definition in individual groups." Anyone have any idea?



  Yes, the fetch-depth in the field definition can be overridden by the fetch-depth in individual groups.


    2. When I save the first child, the parent and grandparent are also saved. Since all 3 objects were transient before the makePersistent call, they should be in detached state as the spec 13.4.2 said. 



  Right. First they are made persistent by reachability and then they are detached in place.


    Now I changed the parent's name to David, and call makePersistent on child2 having the same parent. Is this legal? 



  It is not legal according to the Proposed Final Draft, but it is legal according to a change the expert group just approved. With the change, attachCopyAll no longer exists and you use makePersistentAll to attach objects or make transient objects persistent. So your usage is correct here.


    or should I call attachCopyAll instead? If it is legal, then what should happen here? The spec has no definition what to expect to a detached-dirty object referenced by the target object. Should JDO save the parent's name?



  Yes. Once JPOX code base has been updated to reflect the latest spec change, attaching a dirty-detached object will affect the cache, and the dirty object should be committed to the database as well as the newly created child2.


    3. What should be the object referenced by the parent field of child2 after the save? 



  When you called makePersistentAll on child2, it became persistent and a copy of its parent was put into the cache. And when you committed the transaction, the instances in the cache were detached. So the parent of child2 is a detached instance that has the new name and is distinct from the original parent.


    Note it is detach-all-on-commit. Should it be the original parent instance, or a new detached-clean instance? If it is later case, then the original detached parent instance become useless. 



  Well, it is still detached, it still has its version number and state, but it's now stale (it can't realistically be used further), and it's therefore not much use. If you are going to use instances after the commit, they should be from the instance graph that was most recently detached.


    Would not be better to have an attach method let the PM manage the instance, so we can get it back after the transaction is committed, using detach-all-on-commit or a detach method?



  This scenario only works if the cache never contains instances with the same persistent object id as instances to be attached. And there are issues with rollback of detached instances that are attached in place.


    4. What kind of instances should I got back from my listAll method? detached-clean or hollow? 



  Regardless of whether the commented-out method is called, you will get detached instances. The effect of the commented-out method is that it creates a copy of the cached instances and detach-all-on-commit doesn't create a copy but detaches in place.


    According to my understanding of detach-all-on-commit, they should be detached-clean, am I right? Do I need to call detachCopyAll to get the detached instances?



  There is no need to call detachCopyAll for this case.


    Thank you for your help in advance!



  You are welcome in arrears.


  Craig


    Tony
  On Nov 28, 2005, at 6:52 AM, Tony Lai wrote:


    Hi,

    Since these questions are about the spec, I hope someone from the expert group can give me the answers.  This is also posted on JDOCentral's forums http://www.jdocentral.com/forums/index.php?s=37b48c123ee46e821f97901d00afaeeb&showtopic=1590.

    First, let me define a couple simple classes for demo purpose.

          CODE 
          public class Person implements DetachCallback {
             private String name;
             private Person parent;
             
             public Person(String name) {
                 this(name, null);
             }
             public Person(String name, Person parent) {
                 this.name = name;
                 this.parent = parent;
             }
             ...getters and setters...

             public String toString() {
                 String parentStr = null;
                 try {
                     Person myParent = getParent();
                     if(myParent != null) {
                         parentStr = myParent.toString();
                     }
                 } catch(Exception x) {
                     //may be caused by field not loaded.  Ignore it for now
                 }
                 return name +"["+System.identityHashCode(this)+"]"+
                     (parentStr == null ? "" : (" parent: " + parentStr));
             }

             public void jdoPreDetach() {}
             public void jdoPostDetach(Object detached) {
                 System.out.println("jdoPostDetach: "+name);
             }
          }

          public class DetachTest {
             protected PersistenceManager pm;

             Person grandParent = new Person("Bob");
             Person parent = new Person("Dave", grandParent);
             Person child1 = new Person("John", parent);
             Person child2 = new Person("Mary", parent);
             
             public DetachTest () {
                 pm = createPersistenceManager();
                 pm.setDetachAllOnCommit(true);
             }
             
             public void test() {
                 //This should save child1, parent, and grandParent.
                 makePersistent(child1);
                 System.out.println(child1);

                 // Now change the parent name
                 parent.setName("David");
                 makePersistent(child2);
                 System.out.println(child2);
                 
                 System.out.println();
                 List list = listAll(Person.class, true, "group1");
                 
                 for (Iterator i = list.iterator(); i.hasNext();) {
                     Object obj1 = i.next();
                     System.out.println("    item: "+obj1);
                 }
              }
             
             public static void main(String[] args) {
                 new DetachTest ().test();
             }

             public void makePersistent(Object obj) {
                 Transaction tx = pm.currentTransaction();
                 try {
                     tx.begin();
                     pm.makePersistent(obj);
                     tx.commit();
                 } finally  {
                     rollbackIfActive(tx);
                 }
             }

             public List listAll(Class targetClass, String fetchGroup) {
                 Transaction tx = pm.currentTransaction();
                 Extent extent = null;
                 try {
                     tx.begin();
                     pm.getFetchPlan().setGroup(fetchGroup);

                     List data = new ArrayList();
                     extent = pm.getExtent(targetClass,false);

                     for (Iterator i = extent.iterator(); i.hasNext();) {
                      Object obj1 = i.next();
                      data.add(obj1);
                     }
                     //data = (List)pm.detachCopyAll(data);  // see question 4

                     tx.commit();
                     return data;
                 }  finally {
                     closeIterators(extent);
                     rollbackIfActive(tx);
                 }
             }
             ... some helper methods...
          }

          <jdo>
            <package name="test.jpox.detach">
               <class name="Person" detachable="true">
                  <field name="parent" default-fetch-group="true" fetch-depth="0"/> 
                  <fetch-group name="group1">
                   <fetch-group name="default"/>
                     <field name="parent" fetch-depth="0"/>
                  </fetch-group>
               </class>
          </package>
          </jdo>

         





  Craig Russell

  Architect, Sun Java Enterprise System http://java.sun.com/products/jdo

  408 276-5638 mailto:Craig.Russell@sun.com

  P.S. A good JDO? O, Gasp!