compositeID's and manytomany

1 view
Skip to first unread message

jeff

unread,
Jul 15, 2008, 8:01:47 PM7/15/08
to transfer-dev
Is it possible to use manytomany with compositeID's, kind of like
this:


<compositeid>
<manytomany name="EMPLOYEE_ID" />
<manytomany name="USER_ID" />
</compositeid>

<manytomany name="EMPLOYEES">
<link to="EMPLOYEES.EMPLOYEES" column="EMPLOYEE_ID"/>
</manytomany>
<manytoone name="USERS">
<link to="USERS.USERS" column="USER_ID"/>
</manytomany>

I checked the docs here:
http://docs.transfer-orm.com/wiki/Using_Composite_Keys.cfm

And it doesn't look like manytomany is an option, but I am new to
transfer so I thought I would ask.....

Mark Mandel

unread,
Jul 15, 2008, 8:18:37 PM7/15/08
to transf...@googlegroups.com
Jeff -

How would a m2m work on the DB side as a composite key?

Mark

--
E: mark....@gmail.com
W: www.compoundtheory.com

jeff

unread,
Jul 17, 2008, 2:02:37 PM7/17/08
to transfer-dev
It probably wouldn't :).

Basically, I have a situation like this

TABLE - Sports
SportID
SportName

TABLE - Users
UserID
PeopleName

TABLE - People_Sports_Assocation
UserID
SportID

You may remember this from other classic jeff posts, such as
http://groups.google.com/group/transfer-dev/browse_thread/thread/971e97681b6e460f!
Grabbing this in SQL is a breeze, but I can't get the transfer XML to
work after hours of banging my head against the wall. so i guess a
better question should be:
1) What should be in the sports table object? Many to Many?
2) What should be in the People table object?
3) What should be in the association table if not a composite key?

Thanks again for your help!
> E: mark.man...@gmail.com
> W:www.compoundtheory.com

Jennifer Larkin

unread,
Jul 17, 2008, 2:12:54 PM7/17/08
to transf...@googlegroups.com
As a follow up, I wasn't able to find in the documentation an explanation of what parentonetomany actually does. Understanding that would probably help us out a lot. Thanks
--
I did not come here to get devoured by symbols of monarchy! -- Smirnov of the KGB, Casino Royale

Now blogging....
http://www.blivit.org/blog/index.cfm
http://www.blivit.org/mr_urc/index.cfm

Jon Messer

unread,
Jul 17, 2008, 4:01:24 PM7/17/08
to transf...@googlegroups.com
A parentonetomany signifies that a portion of the compositeid is the part of the compositeid that is being referenced by another (parent) objects OneToMany collection (via the foreign key).

So if your User object has a OneToMany People_Sports_Association collection, then your People_Sports_Assocation object could/would use <parentonetomany class="package.User" /> as part of it's compositeid.


As to the other question, what should be in these objects depends on how you need to use them. There are a few different ways you could model this relationship :

You could have
1) Users ManyToMany Sports
2) Sports ManyToMany Users
3) Users OneToMany People_Sports_Association with either
  3a) Sports OneToMany People_Sports_Association
  or
  3b) People_Sports_Association ManyToOne Sports
4) People_Sports_Association ManyToOne both User and Sport

or the inverse of 3 swapping User and Sport

You can't have ManyToMany on both objects (yet) and you can't choose M2M if there is anything other than the key fields in the link table, as they get cleared and recreated automatically when they get saved.

If there is information in the join table, and you typically go both from a Sport object to a User object but you also go from User objects to Sport objects, then you'd probably want to have  User o2m People_Sports_Association  AND Sport o2m People_Sports_Association.
In this case you'd have 2 parentonetomanies that make up the compositeid of People_Sports_Association

If there is information in the join table and you always (or almost always) go from user to sport, with sport objects being basically just "look up" type objects, then you'd probably want user o2m People_Sports_Association, and People_Sports_Association m2o sport
In this case you'd have one parentonetomany and one manytoone make up the compositeid.

There most certainly are variations I've left out here.

My suggestion is that if you don't have information in People_Sports_Association other than the key fields, use User ManyToMany Sport (no compositeid or join object required).

If there is information in People_Sports_Association other than foreign keys, then you have to choose one of the other models that closest matches how you will use it. My guess would be User o2m People_Sports_Association m2o Sports.

HTH

Mark Mandel

unread,
Jul 17, 2008, 5:45:32 PM7/17/08
to transf...@googlegroups.com
Jen:

Under:
http://docs.transfer-orm.com/wiki/Using_Composite_Keys.cfm#Configuration

The class attribute found on the parentonetomany is the class name of
a object that has a onetomany composite element that points to the
current object configuration.

Let me know if that neesds to be clarified better.

Mark

--
E: mark....@gmail.com
W: www.compoundtheory.com

Mark Mandel

unread,
Jul 17, 2008, 5:46:45 PM7/17/08
to transf...@googlegroups.com
Jeff,

I need to ask if you have looked at any of the same applications out there?

There are several, and they outline many of the relationships that you
can set up, and how you use them.

I highly recommend that you do have a look at the example
applications, as that is what they are there for.

Mark

--
E: mark....@gmail.com
W: www.compoundtheory.com

jeff

unread,
Jul 17, 2008, 6:12:00 PM7/17/08
to transfer-dev
For this case,

All we have are the two ID columns in the association table, and thats
it, so what would my XML look like for the association table object,
just this:

<compositeid>
<property name="UserID" />
<property name="SportID" />
</compositeid>

And no manytomany in the association object?

But I would put the manytomany in the Users Table and the Sports
table, and link it back ot the association table? Is that correcT?



That seems weird since UserID is NOT actually an ID


On Jul 17, 1:01 pm, "Jon Messer" <sylvan.mes...@gmail.com> wrote:
> A parentonetomany signifies that a portion of the compositeid is the part of
> the compositeid that is being referenced by another (parent) objects
> OneToMany collection (via the foreign key).
>
> So if your User object has a OneToMany People_Sports_Association collection,
> then your People_Sports_Assocation object could/would use <parentonetomany
> class="package.User" /> as part of it's compositeid.
>
> As to the other question, what should be in these objects depends on how you
> need to use them. There are a few different ways you could model this
> relationship :
>
> You could have
> 1) Users ManyToMany Sports
> 2) Sports ManyToMany Users
> 3) Users OneToMany People_Sports_Association with either
> 3a) Sports OneToMany People_Sports_Association
> or
> 3b) People_Sports_Association ManyToOne Sports
> 4) People_Sports_Association ManyToOne both User and Sport
>
> or the inverse of 3 swapping User and Sport
>
> You can't have ManyToMany on both objects (yet) and you can't choose M2M if
> there is anything other than the key fields in the link table, as they get
> cleared and recreated automatically when they get saved.
>
> If there *is* information in the join table, and you typically go both from
> a Sport object to a User object but you also go from User objects to Sport
> objects, then you'd probably want to have User o2m
> People_Sports_Association AND Sport o2m People_Sports_Association.
> In this case you'd have 2 parentonetomanies that make up the compositeid of
> People_Sports_Association
>
> If there *is* information in the join table and you always (or almost
> always) go from user to sport, with sport objects being basically just "look
> up" type objects, then you'd probably want user o2m
> People_Sports_Association, and People_Sports_Association m2o sport
> In this case you'd have one parentonetomany and one manytoone make up the
> compositeid.
>
> There most certainly are variations I've left out here.
>
> My suggestion is that if you don't have information in
> People_Sports_Association other than the key fields, use User ManyToMany
> Sport (no compositeid or join object required).
>
> If there is information in People_Sports_Association other than foreign
> keys, then you have to choose one of the other models that closest matches
> how you will use it. My guess would be User o2m People_Sports_Association
> m2o Sports.
>
> HTH
>
> On Thu, Jul 17, 2008 at 11:12 AM, Jennifer Larkin <jlar...@gmail.com> wrote:
> > As a follow up, I wasn't able to find in the documentation an explanation
> > of what parentonetomany actually does. Understanding that would probably
> > help us out a lot. Thanks
>
> > On Thu, Jul 17, 2008 at 11:02 AM, jeff <jeff.gladn...@gmail.com> wrote:
>
> >> It probably wouldn't :).
>
> >> Basically, I have a situation like this
>
> >> TABLE - Sports
> >> SportID
> >> SportName
>
> >> TABLE - Users
> >> UserID
> >> PeopleName
>
> >> TABLE - People_Sports_Assocation
> >> UserID
> >> SportID
>
> >> You may remember this from other classic jeff posts, such as
>
> >>http://groups.google.com/group/transfer-dev/browse_thread/thread/971e...
> >> !

Jon Messer

unread,
Jul 17, 2008, 7:38:59 PM7/17/08
to transf...@googlegroups.com
You would have a manytomany in either User or Sport (it cannot be in both), and you would not even define the association object, it doesn't exist...  ;-)

          <object name="User" table="Users">
              <id name="UserId" />
              <manytomany name="Sport" table="Sports">
                  <link to="package.User" column="UserID"/>
                  <link to="package.Sport" column="SportID"/>
                  <collection type="array" />
              </manytomany>
...

Jon Messer

unread,
Jul 17, 2008, 7:40:33 PM7/17/08
to transf...@googlegroups.com
woops I gotta proof read  :


          <object name="User" table="Users">
              <id name="UserId" />
              <manytomany name="Sport" table="People_Sports_Assocation">

                  <link to="package.User" column="UserID"/>
                  <link to="package.Sport" column="SportID"/>
                  <collection type="array" />
              </manytomany>

jeff

unread,
Jul 17, 2008, 7:54:05 PM7/17/08
to transfer-dev
Ok, I figured it out, and for posterity sake, heres how I did it:

In the Users Package:

<onetomany name="USER_SPORTS" lazy="true">
<link to="USER_SPORTS.USER_SPORTS" column="USERID"/>
<collection type="array">
<order property="USERID" order="asc"/>
</collection>
</onetomany>

In the association package:

<compositeid>
<parentonetomany class="USERS.USERS" />
<parentonetomany class="SPORTS.SPORTS" />
</compositeid>

<property name="USERID" type="numeric" column="USERID" />
<property name="SPORTID" type="numeric" column="SPORTID" />


And in the Sports Package


<onetomany name="USER_SPORTS" lazy="true">
<link to="USER_SPORTS.USER_SPORTS" column="SPORTID"/>
<collection type="array">
<order property="SPORTID" order="asc"/>
</collection>
</onetomany>

jeff

unread,
Jul 17, 2008, 7:59:10 PM7/17/08
to transfer-dev
Also, in case anyone is curious, you have to treat this a little
differently when doing a transfer.get(), and
1) pass in the compositeID's as a STRUCT!!!
2) prepend the compositeID with the word "parent"

For example

<cfset var composite = StructNew()>
<cfset composite.parentUSERS = 2 />
<cfset composite.parentSPORTS = 1 />

<cfset blah = transfer.get('USER_SPORTS.USER_SPORTS",composite)>

That would return one row with USERID 2 and SPORTID 1

Loony2nz

unread,
Jul 18, 2008, 1:56:51 PM7/18/08
to transfer-dev
Now I have a question...

How do you do an update with a composite key?

I have a similar situation where I did the read of the record with the
composite key.
Now I have the record in a transfer object.
I do some manipulation on the object (do some sets).

Now how do I save the manipulated record?

I tried: transfer.save(blah)

But, it hung my system and stayed in an infinite loop. I just watched
my memory allocation climb endlessly.

Is there something special needed to do to the save method when saving
a composite key?

Jon Messer

unread,
Jul 18, 2008, 2:14:20 PM7/18/08
to transf...@googlegroups.com
Having the USERID and SPORTID defined as properties is going to give you problems when you go to save (as in it won't work). 

Jon Messer

unread,
Jul 18, 2008, 2:15:49 PM7/18/08
to transf...@googlegroups.com
You probably have relationships set up on both ends somewhere, which will cause infinite loops. That or you are using a xToMany that loads a boat load of objects on the many side.

jeff

unread,
Jul 18, 2008, 5:42:54 PM7/18/08
to transfer-dev

Jon is correct, transfer attempts the following query when the
properties exist:

INSERT INTO USER_SPORTS(SPORTID, USERID,SPORTID, USERID) VALUES (....

effectively doubling them up. We're rethinking this....


On Jul 18, 11:14 am, "Jon Messer" <sylvan.mes...@gmail.com> wrote:
> Having the USERID and SPORTID defined as properties is going to give you
> problems when you go to save (as in it won't work).
>

Jon Messer

unread,
Jul 18, 2008, 5:49:10 PM7/18/08
to transf...@googlegroups.com
I would ask why do you need those as properties? You can grab the user object by userid and get to the related user_sport objects and by extension the related sports objects and the same is true for sport in the other direction. So what use case would require those ids as properties on the user_sports object, that could not be done by going through the parent user and sport objects?

jeff

unread,
Jul 18, 2008, 6:51:49 PM7/18/08
to transfer-dev
We were able to do that for a single record, but is it possible to do
a listbyproperty, or even write your own TQL to retrieve table data if
there are no properties for the object in transfer.xml?

So if I wanted to get all the SPORTID's the the USER_SPORTS table if
the USERID = 2, how would I do that?

On Jul 18, 2:49 pm, "Jon Messer" <sylvan.mes...@gmail.com> wrote:
> I would ask why do you need those as properties? You can grab the user
> object by userid and get to the related user_sport objects and by extension
> the related sports objects and the same is true for sport in the other
> direction. So what use case would require those ids as properties on the
> user_sports object, that could not be done by going through the parent user
> and sport objects?
>

Daniel Short

unread,
Jul 19, 2008, 9:49:56 AM7/19/08
to transf...@googlegroups.com
I'm dealing with the same mental hurdle right now...

I have Users, which have onetomany Groups. My transfer definition
looks like this:

<package name="Users">
<object name="User" table="Users" decorator="_model.Users.UserDecorator">
<id name="ID" type="numeric" />
<property name="Username" type="string" column="Username" />
<property name="Password" type="string" column="Password" />
<property name="FirstName" type="string" column="FirstName" />
<property name="LastName" type="string" column="LastName" />
<property name="EmailAddress" type="string" column="EmailAddress" />
<property name="Confirmed" type="boolean" column="Confirmed" />
<property name="GUID" type="string" column="GUID" />
<property name="stamp" type="date" column="stamp" />
<property name="stampupdated" type="date" column="stampupdated" />

<onetomany name="Groups" lazy="true">
<link to="Groups.Group" column="UserID"/>
<collection type="array">
<order property="SortOrder" order="asc" />
</collection>
</onetomany>

</object>
</package>


<package name="Groups">
<object name="Group" table="Groups" decorator="_model.Groups.GroupDecorator">
<id name="ID" type="numeric" />
<!--
Don't set this as a property since it's part of a manytoone relationship
<property name="UserID" type="numeric" column="UserID" />
-->
<property name="GroupLabel" type="string" column="GroupLabel" />
<property name="SortOrder" type="numeric" column="SortOrder" />
<property name="stamp" type="date" column="stamp" />
<property name="stampupdated" type="date" column="stampupdated" />

<manytomany name="Items" table="GroupsItems">
<link to="Groups.Group" column="GroupID"/>
<link to="Items.Item" column="ItemID"/>


<collection type="array" />
</manytomany>

</object>
</package>
</package>


If I try to do something like this in a validate method it fails:

<cfset LOCAL.PropertyMap = {UserID = getUserID(), GroupLabel =
getGroupLabel()} />
<cfset LOCAL.groupnameCheck =
getTransfer().listByPropertyMap("Groups.Group", LOCAL.PropertyMap) />

It fails with:

The property 'USERID' could not be found in the object 'Groups.Group'

It seems to me that I should have implicit access to that property
since it's a foreign key in the table... If I add it as a property to
the Groups I get duplicate column name errors from SQL. It seems to me
wasteful that I always have to go get the parent object before I can
get the children. It also complicates the application as a whole since
intead of the two line bit of code above to check and see whether a
group name already exists for a user, I either have to get a user
object first, or I have to write TQL to do it instead.

Dan

Reply all
Reply to author
Forward
0 new messages