【问题标题】:CF ORM many-to-many relationship sort orderCF ORM 多对多关系排序顺序
【发布时间】:2013-11-08 01:18:50
【问题描述】:

我有一个多对多关系设置,需要控制顺序。

我有一个具有以下属性的实体。通过这种关系检索时如何控制组件的顺序?

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

我在链接表 (CMSPageComponents) 中设置了一个名为 dispOrder 的列。但是当我在上面的属性上设置orderby="dispOrder"orderby="CMSPageComponents.dispOrder" 属性时,它似乎忽略了它。

关于如何控制多对多关系的顺序有什么建议吗?

【问题讨论】:

  • AFAIK 多对多实际上并没有被广泛使用并且非常有限。试着把它变成一对多,排序顺序应该会得到很好的支持。
  • 是的,一对多确实很容易排序,但我需要多对多。一对多并没有提供我需要的功能。
  • 什么功能?多对多基本上只是一对一对多的关系。如果您希望 orderby 在链接表上有一列,afaik 将其提升为实体是您需要做的。

标签: orm coldfusion coldbox


【解决方案1】:

当关系是多对多时,CF 会将orderBy 语句应用于对象表而不是链接表。因此,理论上您可以将 dispOrder 列从 CMSPageComponents 链接表移动到 CmsComponent 表以使其工作。

但在实践中,我希望排序特定于多对多关系(即特定页面),在这种情况下,您可以遵循彼得的建议并创建一个单独的实体来链接其他两个实体并让您定义一个订单属性。

所以你会有 3 个实体:

  1. CmsPage
  2. CmsComponent
  3. CmsPageComponent

CmsPageComponent 可能看起来像这样:

<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 可以与链接实体建立一对多的关系,从而允许使用 dispOrder 列进行排序:

<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>

更新 下面展示了如何添加和显示页面组件。不是唯一或必然是最好的方法,只是为了给你一个想法:

<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>

注意:这假设 ORM 设置 flushAtRequestEnd 在 Application.cfc 中为真

【讨论】:

  • 感谢 CFSimplicity!感谢您的解释,我想我明白彼得现在的意思了。但我仍然看不出这如何模拟多对多。我想不出如何将组件添加到页面或获取组件列表而不会成为一个复杂的过程?我是否最好只恢复到标准 SQL 查询来检索具有当前多对多设置的组件?再次比你!
  • 我在示例中添加了更多代码,以展示您可以使用中间对象关系添加和显示组件。当然,这更令人费解,但确实为您提供了更大的灵活性,并解决了 CF 对多对多订购的限制。
  • 谢谢 CfSimplicity!那是一种享受。我实际上认为实施起来会很混乱,但最后,除了设置一个多对多之外,没有什么比这更重要的了。谢谢!
猜你喜欢
  • 2015-07-28
  • 2012-02-20
  • 1970-01-01
  • 1970-01-01
  • 2016-04-07
  • 2011-08-23
  • 1970-01-01
  • 2011-06-22
  • 1970-01-01
相关资源
最近更新 更多