Question

I have a many to many relationship setup, and need to control the order.

I have an entity with the property below. How do I control the order of the components when retrieved via this relationship?

property name="Components" fieldtype="many-to-many" cfc="CmsComponent" 
      type="array" 
      singularname="Component" 
      linktable="CMSPageComponents" 
      fkcolumn="page_id" 
      inversejoincolumn="component_id";

I've setup a column in the linktable (CMSPageComponents) called dispOrder. But when I set the orderby="dispOrder" or orderby="CMSPageComponents.dispOrder" attribute on the property above, it just seems to ignore it.

Any suggestions on how I can control the order of a many-to-many relationship?

Was it helpful?

Solution

When the relationship is many-to-many CF will apply the orderBy statement to the object table not to the link table. So in theory you could move your dispOrder column from the CMSPageComponents link table to the CmsComponent table to make it work.

But in practice I expect the ordering is specific to the many-to-many relationship (i.e. the particular page), in which case you could follow Peter's advice and create a separate entity which links the other two entities and lets you define an order property.

So you would have 3 entities:

  1. CmsPage
  2. CmsComponent
  3. CmsPageComponent

CmsPageComponent might look something like this:

<cfcomponent displayname="CmsPageComponent" persistent="true" table="cmsPageComponents">
    <!--- Add a primary key for the link Entity --->
    <cfproperty name="ID" fieldType="id" generator="native">
    <cfproperty name="dispOrder">
    <cfproperty name="page" fieldType="many-to-one" cfc="CmsPage" fkColumn="pageID">
    <cfproperty name="component" fieldType="many-to-one" cfc="CmsComponent" fkColumn="componentID">
    <!--- init() etc --->
</cfcomponent>

CmsPage could then have a one-to-many relationship with the link entity allowing ordering using the dispOrder column:

<cfcomponent displayname="CmsPage" persistent="true" table="cmsPages">
    <cfproperty name="ID" fieldType="id" generator="native">
    <cfproperty name="pageComponents" singularName="pageComponent" fieldType="one-to-many" cfc="PageComponent" fkColumn="pageID" orderBy="dispOrder">
    <!--- init() etc --->
</cfcomponent>

Update The following shows how you might add and display page components. Not the only or necessarily best way, but just to give you an idea:

<cfscript>
transaction{
    //load the page
    page    =   EntityLoadByPK( "CmsPage",1 );
    //load the components we want to add
    component1  =   EntityLoadByPK( "CmsComponent",1 );
    component2  =   EntityLoadByPK( "CmsComponent",2 );
    //create link objects
    pageComponent1  =   EntityNew( "CmsPageComponent" );
    pageComponent2  =   EntityNew( "CmsPageComponent" );
    // link them to the pages and components in the order we want
    pageComponent1.setComponent( component1 );
    pageComponent1.setPage( page );
    pageComponent1.setDispOrder( 2 );
    EntitySave( pageComponent1 );
    pageComponent2.setComponent( component2 );
    pageComponent2.setPage( page );
    pageComponent2.setDispOrder( 1 );
    EntitySave( pageComponent2 );
}
//Reload from the database so the order is applied
EntityReload( page );
</cfscript>
<!DOCTYPE html>
<html>
<head>
    <title>Test</title>
</head>
<body>
    <cfoutput>
        <h2>Page #page.getID()#</h2>
        <ol>
            <cfloop array="#page.getPageComponents()#" index="pageComponent">
                <cfset component    =   pageComponent.getComponent()>
                <li>Component ID #component.getID()#, Display Order = #pageComponent.getDispOrder()#)</li>
            </cfloop>
        </ol>
    </cfoutput>
</body>
</html>

NOTE: this assumes the ORM setting flushAtRequestEnd is true in Application.cfc

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top