Shouldn't have to do that, but it depends, in part, on how things are
modeled.
Cayenne can manage the relationship object graph for you.
In older versions of cayenne, you had to explicitly register E1 before
associating it with E2. In current versions of cayenne, as long as /
one/ of the entities is registered with an object context, you can
associate the two entities, and if the other is not registered, it
will be auto-registered (note: if both objects are registered, but
they are registered to different object contexts, you'll get an
exception).
So, for Question 1:
E2 e2 = new E2();
e1.addToE2List(e2);
or
E2 e2 = new E2();
e2.setE1(e1);
or
//following is 3.0M5-based code
ObjectContext oc = BaseContext.getThreadObjectContext();
E2 e2 = oc.newObject(E2.class);
e2.setE1(e1);
or
ObjectContext oc = BaseContext.getThreadObjectContext();
E2 e2 = oc.newObject(E2.class);
e1.addToE2List(e2);
Any of those will work just fine and be equivalent.
For Question 2:
At least in 3.0, as long as your relationships are properly mapped,
simply doing:
ObjectContext oc = BaseContext.getThreadObjectContext();
oc.deleteObject(e2);
oc.commitChanges();
Will work, and the object should be removed from all associated
relationships.
For example, using 3.0M5, I just wrote the following test (which
passes) in a project of mine to illustrate the behavior.
Note that "createRole" is a convenience method which creates a
UserRole, registers it with the thread-bound ObjectContext, sets
default properties, and commits the object to the database.
UserRole has a one-to-many relationship with Parent. Conversely,
Parent has a ManyToOne relationship with UserRole.
public void testRelationshipDeleting() {
ObjectContext oc = BaseContext.getThreadObjectContext();
UserRole role = createRole("test role");
Parent p = new Parent();
p.setUsername("somelogin");//username and password are required.
p.setPassword("somepassword");
p.setUserRole(role);
assertTrue(role.getParentsInRole().contains(p)); //note that even
before the commit, cayenne has updated the object graph so the parent
is in the list.
oc.commitChanges();
assertTrue(role.getParentsInRole().contains(p));
oc.deleteObject(p);
assertFalse(role.getParentsInRole().contains(p));//note that even
before committing changes, the parent has been removed from the
relationship.
oc.commitChanges();
assertFalse(role.getParentsInRole().contains(p));
}
One line of code you have below has me raising my eyebrows a bit, and
that's the dc.commitChangesToParent(). That's only used/needed for
nested data contexts. Based on the rest of your code, it doesn't look
like you're using nested data contexts. See: http://cayenne.apache.org/doc/nested-datacontexts.html
for more information.
Suffice it to say that you probably don't need
dc.commitChangesToParent();
Robert
On Dec 26, 2008, at 12/261:05 PM , Joe Baldwin wrote:
This accounts for the totally weird results. Ref to "what [I]
want". As usual with software, I would like to make a change in one
place vs two or three places. I guess I am still thinking of this
from a RDB point of view. It sounds like you are telling me, that I
must update all of the relationships via explicit code references
and then commitChanges.
Is this correct?
On Dec 26, 2008, at 2:19 PM, Pierre Lavignotte wrote:
Hi Joe,
Question 1 :
you can't call the object constructor. Use the DataContext method
instead
because it will register the object too.
Question 2 :
It depends what you want !
DataContext dc = DataContext.
getThreadDataContext();
E1.getE2List().remove(e2);
dc.commitChanges();
This will remove the link between E1 and E2 but E2 will still exist.
DataContext dc = DataContext.
getThreadDataContext();
dc.deleteObject(e2);
dc.commitChangesToParent();
dc.commitChanges();
This will delete E2... but I think it will still be present in
E1.getE2List() because the list can be in memory.
I know it's not logical but I'm quite sure I allready encontered
this case.
I use Cayenne 2.0.4 so Cayenne 3.0 can differ in some points.
Pierre
Cordialement,
Pierre Lavignotte
Ingénieur Conception & Développement
http://pierre.lavignotte.googlepages.com
On Fri, Dec 26, 2008 at 6:32 PM, Joe Baldwin
<[email protected]>wrote:
I have a few questions about best practices. I have done some
experimenting, have read what I could find, and have some
questions about
some elementary Cayenne usage concerning Add & Delete with a
Parent-ChildList design. (I have recently experienced some odd
behavior
that may be due to a fundamental misunderstanding of DataContext
rules.)
Environment: I am using 3.0 M4 with MySQL and Tomcat JSP
DataContext: I am getting the context using:
DataContext.getThreadDataContext();
Example Design:
E1 has a list of E2's
that is:
E2 is a child of E1 and is a many-to-one relationship.
The E1 relationship is called "E2List" and the reverse
relationship
on E2 is called "E1".
Questions:
1. When creating and associating E2 children is it more proper to
do the
following:
DataContext dc = DataContext.getThreadDataContext();
** [get E1 via a DataContext query]
E2 e2 = new E2();
e2.setE1(e1); // I **assume** this registers e2 with the
Context &
adds e2 to e1's list
dc.commitChanges();
OR do you need to do as your example suggests:
DataContext dc = DataContext.getThreadDataContext();
E2 e2 = (E2) dc.newObject(E2.class);
e2.setE1(e1);
dc.commitChanges();
OR is there a better way?
2. Removal of a Child
Can you remove the child using:
DataContext dc = DataContext.getThreadDataContext();
dc.deleteObject(e2);
dc.commitChangesToParent();
dc.commitChanges();
or must you do it via the parent:
DataContext dc = DataContext.getThreadDataContext();
E1.getE2List().remove(e2);
dc.commitChanges();
(Note: the second method seems to work better.)
Thanks,
Joe