Parent/Child Bidirectional Relationship Woes

62 views
Skip to first unread message

CoderDave

unread,
Apr 15, 2010, 1:43:42 PM4/15/10
to cf-orm-dev
From what I've read, when in a bidirectional relationship, it's better
(Domain Model Integrity) to set both sides of the relationship. To
quote this article:
http://www.briankotek.com/blog/index.cfm/2009/12/16/Bidirectional-Association-Management-in-ColdFusion-9-ORM
"If I don't explicitly set both sides of the relationship, and if the
Child doesn't do something to enforce this bidirectional relationship,
it won't get set."

So I've set up a very simple example.

PARENT
component persistent="true" table="Parent" {
property name="id" column="ParentID" fieldtype="id"
generator="native" setter="false";
property name="Children" singularname="Child" fieldtype="one-to-many"
inverse="true" cfc="Child" fkcolumn="ParentID";
}

CHILD
component persistent="true" table="Child" {
property name="id" column="ChildID" fieldtype="id" generator="native"
setter="false";
property name="Parent" fieldtype="many-to-one" cfc="Parent"
fkcolumn="ParentID";
}

TEST CODE:
oParent = entityNew("Parent");
oChild = entityNew("Child");

oParent.addChild(oChild);
oChild.setParent(oParent);

writeOutput("<br>oParent.hasChild(oChild): " &
oParent.hasChild(oChild));
writeOutput("<br>oChild.hasParent(oParent): " &
oChild.hasParent(oParent));

entitySave(oParent);
EntitySave(oChild);

OUTPUT:
oParent.hasChild(oChild): YES
oChild.hasParent(oParent): NO

What happened? Why doesn't the Child see its Parent? I thought if I
set both sides of the relationship, I won't have these problems?

Bob Silverberg

unread,
Apr 15, 2010, 2:03:33 PM4/15/10
to cf-or...@googlegroups.com
That actually looks to be a bug with the hasParent() method. You are calling it incorrectly - the hasParent() method does not accept an argument, because there can only be one parent.  So your call to oChild.hasParent(oParent) is incorrect - it should just be oChild.hasParent().  I believe you'll find if you change that they it will return TRUE.

That does not change the fact that your call to oChild.hasParent(oParent) did not generate an error, and in fact returned FALSE.  That to me is a bug and should be reported to Adobe.

Bob


--
You received this message because you are subscribed to the Google Groups "cf-orm-dev" group.
To post to this group, send email to cf-or...@googlegroups.com.
To unsubscribe from this group, send email to cf-orm-dev+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/cf-orm-dev?hl=en.




--
Bob Silverberg
www.silverwareconsulting.com

Hands-on ColdFusion ORM Training @ cf.Objective() 2010
www.ColdFusionOrmTraining.com


CoderDave

unread,
Apr 15, 2010, 2:34:57 PM4/15/10
to cf-orm-dev
That would be the problem and I agree it should error. Thanks!

On Apr 15, 2:03 pm, Bob Silverberg <bob.silverb...@gmail.com> wrote:
> That actually looks to be a bug with the hasParent() method. You are calling
> it incorrectly - the hasParent() method does not accept an argument, because
> there can only be one parent.  So your call to oChild.hasParent(oParent) is
> incorrect - it should just be oChild.hasParent().  I believe you'll find if
> you change that they it will return TRUE.
>
> That does not change the fact that your call to oChild.hasParent(oParent)
> did not generate an error, and in fact returned FALSE.  That to me is a bug
> and should be reported to Adobe.
>
> Bob
>
>
>
> On Thu, Apr 15, 2010 at 1:43 PM, CoderDave <coderd...@gmail.com> wrote:
> > From what I've read, when in a bidirectional relationship, it's better
> > (Domain Model Integrity) to set both sides of the relationship. To
> > quote this article:
>

> >http://www.briankotek.com/blog/index.cfm/2009/12/16/Bidirectional-Ass...

> > cf-orm-dev+...@googlegroups.com<cf-orm-dev%2Bunsu...@googlegroups.com>

Rupesh Kumar

unread,
Apr 15, 2010, 11:20:13 PM4/15/10
to cf-or...@googlegroups.com
Did you log any bug for this? If not, can you log one?

Thanks,
Rupesh

--
You received this message because you are subscribed to the Google Groups "cf-orm-dev" group.
To post to this group, send email to cf-or...@googlegroups.com.
To unsubscribe from this group, send email to cf-orm-dev+...@googlegroups.com.

CoderDave

unread,
Apr 16, 2010, 10:14:13 AM4/16/10
to cf-orm-dev
I'll have to log that bug Rupesh, thanks.
Another problem though. Also from what I've read, you generally only
have to define the association method on the side with inverse="true".
However, my hasChild method returns "NO" when I have the association
method on just the Parent side.

PARENT.cfc
component persistent="true" table="Parent" {
property name="id" column="ParentID" fieldtype="id"
generator="native" setter="false";
property name="Childs" singularname="Child" fieldtype="one-to-many"
inverse="true" cfc="Child" fkcolumn="ParentID";

// association management method to ensure Domain Model Integrity
public function addChild(oChild) {

// first relate child to this parent
variables.Childs = [arguments.oChild];

// now relate this parent to child if it's missing
if (!IsNull(arguments.oChild) &&
!arguments.oChild.hasParent())
{
arguments.oChild.setParent(this);
}
}
}

CHILD.cfc
component persistent="true" table="Child" {
property name="id" column="ChildID" fieldtype="id"
generator="native" setter="false";
property name="Parent" fieldtype="many-to-one" cfc="Parent"
fkcolumn="ParentID";
}

TEST.cfm
oParent = entityNew("Parent");
oChild = entityNew("Child");

oChild.setParent(oParent);

writeOutput("<br>oParent.hasChild(oChild): " &
oParent.hasChild(oChild));
writeOutput("<br>oChild.hasParent(): " & oChild.hasParent());

EntitySave(oParent);
EntitySave(oChild);

OUTPUT
oParent.hasChild(oChild): NO
oChild.hasParent(): YES

Am I doing something wrong? However, if I also put an association
method on the Child side, both of my has methods return true, whether
I use oChild.setParent(oParent) or oParent.addChild(oChild). So it
seems like I need both association methods for true "Domain Model
Integrity"?

Bob Silverberg

unread,
Apr 16, 2010, 10:54:32 AM4/16/10
to cf-or...@googlegroups.com
On Fri, Apr 16, 2010 at 10:14 AM, CoderDave <code...@gmail.com> wrote:

PARENT.cfc
component persistent="true" table="Parent" {
  property name="id" column="ParentID" fieldtype="id"
generator="native" setter="false";
  property name="Childs" singularname="Child" fieldtype="one-to-many"
inverse="true" cfc="Child" fkcolumn="ParentID";

  // association management method to ensure Domain Model Integrity
  public function addChild(oChild) {

     // first relate child to this parent
     variables.Childs = [arguments.oChild];

That line (just above), doesn't seem right.  You will always end up with an array with just one child using that code.  I'm not trying to self-promote here, but I did recently write a blog post on this topic, which can be found at:  http://www.silverwareconsulting.com/index.cfm/2010/4/2/Managing-Bidirectional-Relationships-in-ColdFusion-ORM--Arraybased-Collections-Followup

Barney Boisvert (http://www.barneyb.com/barneyblog/) and Brian Kotek (http://www.briankotek.com/blog/) have also written about this issue. I highly recommend you read what they've written as I think it makes the issue very clear.

Cheers,
Bob

--
Bob Silverberg

www.silverwareconsulting.com

Hands-on ColdFusion ORM Training @ cf.Objective() 2010
www.ColdFusionOrmTraining.com


CoderDave

unread,
Apr 16, 2010, 1:42:03 PM4/16/10
to cf-orm-dev
Thanks, I read your article. What would the functions be if it was
just a one to many relationship, or even a one to one relationship?
For example, what if one Country had many Languages or only one
Country had one Language. (I know that's a bad example but I wanted to
keep it in the context of your article.)

On Apr 16, 10:54 am, Bob Silverberg <bob.silverb...@gmail.com> wrote:
> On Fri, Apr 16, 2010 at 10:14 AM, CoderDave <coderd...@gmail.com> wrote:
>
> > PARENT.cfc
> > component persistent="true" table="Parent" {
> >   property name="id" column="ParentID" fieldtype="id"
> > generator="native" setter="false";
> >    property name="Childs" singularname="Child" fieldtype="one-to-many"
> > inverse="true" cfc="Child" fkcolumn="ParentID";
>
> >    // association management method to ensure Domain Model Integrity
> >   public function addChild(oChild) {
>
> >      // first relate child to this parent
> >      variables.Childs = [arguments.oChild];
>
> That line (just above), doesn't seem right.  You will always end up with an
> array with just one child using that code.  I'm not trying to self-promote
> here, but I did recently write a blog post on this topic, which can be found
> at:http://www.silverwareconsulting.com/index.cfm/2010/4/2/Managing-Bidir...

Bob Silverberg

unread,
Apr 16, 2010, 1:49:23 PM4/16/10
to cf-or...@googlegroups.com
Unfortunately I don't have time right now to put together an example for you (too busy getting ready for cf.Objective()), but the concepts that I discuss in that article and the previous one (that article was a follow-up) apply.  Why don't you just give it a try and see what works?  Just dump your objects after the setting has been done and you should see whether or not the correct results have been achieved.  I wouldn't use the has() methods to check this - just dump the objects and you'll be able to see if the composition is correct or not.

Cheers,
Bob


Hands-on ColdFusion ORM Training @ cf.Objective() 2010
www.ColdFusionOrmTraining.com


Reply all
Reply to author
Forward
0 new messages