这张图片展示了我想要实现的目标。左边是表格数据,右边是我要创建的表格。
该表使用 parentID 来引用同一个表中的另一个项目以创建层次结构。
我将如何以这种方式创建查询并组织它们?
如果我选择“海盗”并想要得到所有的父母怎么办?CFML 中有什么东西比循环查询更容易,直到我到达顶部?
这张图片展示了我想要实现的目标。左边是表格数据,右边是我要创建的表格。
该表使用 parentID 来引用同一个表中的另一个项目以创建层次结构。
我将如何以这种方式创建查询并组织它们?
如果我选择“海盗”并想要得到所有的父母怎么办?CFML 中有什么东西比循环查询更容易,直到我到达顶部?
您的分层数据使用称为邻接列表的方法表示。还有许多其他选项,您最终使用的选项取决于数据更改的频率以及您使用的底层数据库 - 其中一些具有便于查询邻接列表的功能 - 其中主要是公用表表达式(CTE)。有关使用其他数据库的方法,请参阅链接的问题。
使用 CTE,您可以按顺序从邻接列表中检索层次结构并计算每个条目的“级别” - 在您的情况下正确缩进。如果您的数据库没有 CTE 并且没有其他轻松查询的方法,请考虑使用不同的方法,嵌套集可能是最容易访问的,其中检索速度很快,但代价是更复杂的更改算法(即插入、删除、移动)。
我还没有测试过这个...... :)
<!--- item.cfc --->
<cfcomponent persistent="true" cache="read-only">
<cfproperty name="id" fieldtype="id">
<cfproperty name="parent"
fieldtype="many-to-one" cfc="item" fkcolumn="ParentID">
<cfproperty name="children" type="array"
fieldtype="one-to-many" cfc="item" fkcolumn="ParentID" inverse="true">
</cfcomponent>
<!--- display.cfm --->
<cffunction name="printItem" output="true">
<cfargument name="item" required="true">
<table>
<tr>
<td>#item.getName()#
<cfif item.hasChildren()>
<table>
<cfloop array="#item.getChildren()#" index="local.i">
<tr>
<td>#printItem(local.i)#
</cfloop>
</table>
</cfif>
</table>
</cffunction>
<cfset printItem( entityLoadByPK("item",1) )>
在考虑类似需求时,我考虑过的一种方法是异步构建层次结构 - 即使用 AJAX 请求。根据您的需要,这可能适合您,也可能不适合您,但想象一下,您不是立即构建整个树,而是最初只向用户展示顶层。然后,当用户选择顶级项目之一时,会发出 AJAX 请求以查找所选项目的子项。根据需要为每个孩子重复构建树。这样一来,问题就很简单了,实现它的查询和代码也很简单。
这是我在你的帮助下想出的。
<!--- adjacency list display --->
<cffunction name="adjacentList" output="true">
<cfargument name="alQuery" required="true">
<cfargument name="qid" required="false" default="0">
<cfquery name="alSubQuery" dbtype="query">
SELECT * FROM alQuery WHERE parentID=#qid#
</cfquery>
<cfif alSubQuery.RecordCount neq 0>
<ul>
<cfloop query="alSubQuery">
<li>
#name#
#adjacentList(#alQuery#,#id#)#
</li>
</cfloop>
</ul>
</cfif>
</cffunction>
使用:#adjacentList(#query#)#