代码之家  ›  专栏  ›  技术社区  ›  azzy81

推进ORM自引用外键

  •  4
  • azzy81  · 技术社区  · 13 年前

    我正在使用Propel ORM,这对Propel来说是全新的。我需要一些帮助,从一个查询不正确的表中选择数据。我有一张这样的桌子(注意:不是实际的桌子,而是同一张桌子):

    +---------------------+
    | ID  | Page | Parent |
    +---------------------+
    | 1   |  A   |  0     |
    | 2   |  B   |  0     |
    | 3   |  C   |  2     |
    | 4   |  D   |  3     |
    | 5   |  E   |  1     |
    | 6   |  F   |  0     |
    | 7   |  G   |  3     |
    | 8   |  H   |  4     |
    | 9   |  I   |  6     |
    | 10  |  J   |  5     |
    +---------------------+
    

    这个表在加载页面时给了我一个树状结构。在使用推进之前,我有一个函数为“loadPages”的类,它会将内部页面嵌套在一个名为$的数组上,嵌套在pages类中,看起来像这样(注意:不是实际的函数,只是一个封闭的表示):

    function loadPages($parent=0, $data){
        $sql = "sql query here to select pages where parent = $parent";
        while($results){
           $pages = new Pages();
           $pages->setId(blah blah);
           $pages->setPage(blah blah);
           $pages->setParent(blah blah);
    
           $innerPages = new Pages();
           /* load innerpages into the nested array */
           $innerPages->loadPages($pages->getId(), $pages->nested);
    
           array_push($data, $pages);
           return true;
        }
    }
    

    基本上,我如何使用Propel做到这一点?我可以很容易地拉出父值为0的页面,如下所示:

    $pages = PagesQuery::create()
    ->filterByParent(0)
    ->find();
    

    但我需要将内部页面递归嵌套到它返回的对象,即使Propel网站上有所有好的文档,我的努力也没有取得多大成果。

    对于我的旧Pages类,如果我打印$data,我会得到这样的符号(这里只有一个使用上表的例子):

    Array(
       [0] => Pages Object
       (
        [id] => 2
        [page] => B
        [parent] => 0
        [nested] = Array(
           [0] => Pages Object
           (
            [id] => 3
            [page] => C
            [parent] => 2
           )
        )
    )
    

    我已经做到了,但我不确定这是最好的方法。

    function loadPages($parent=0, $siteId, &$arr){
            $arr = PagesQuery::create()
            ->filterBySiteId($siteId)
            ->filterByParentId($parent)
            ->find();
    
            foreach ($arr as $i => $v) {
                $arr[$i]->nested = '';
                loadPages($v->getId(), $siteId, $arr[$i]->nested);
            }
    
        }
        $site->pages = '';
        loadPages(0, $site->getId(), $site->pages);
    

    我的模式没有自关系设置,所以我现在像这样在同一个表中添加了一个外键,并重新运行push来重新创建类。我仍然不确定如何写出推进查询(为了节省空间,我从模式中删除了几列)。很抱歉,这篇帖子现在收到了hugh。

    <table name="pages" phpName="Pages">
        <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true"/>
        <column name="userId" type="integer" required="false"/>
        <column name="siteId" type="integer" required="false"/>
        <column name="parentId" type="integer" required="false"/>
        <foreign-key foreignTable="users" phpName="Users" refPhpName="Pages">
             <reference local="userId" foreign="id"/>
            </foreign-key>
        <foreign-key foreignTable="sites">
              <reference local="siteId" foreign="id"/>
            </foreign-key>
            <foreign-key foreignTable="pages">
             <reference local="parentId" foreign="id"/>
            </foreign-key>
    </table>
    
    1 回复  |  直到 13 年前
        1
  •  3
  •   smhg    13 年前

    这不是对你问题的直接回答,但它仍然是一个解决方案。

    正如你在对这个问题的评论中提到的那样: 嵌套集合 答案是。

    起初,这听起来可能是解决问题的一种方法,但嵌套集是其他人遇到类似问题的结果。它经过了充分的研究,是表示树木的一种流行方式。它的主要优势正是能够管理可变深度的树。

    你提到你是Propel的新手,切换到嵌套集需要做很多工作,所以我冒昧地假设你没有使用Propel的 行为 之前如果是这样的话,一定要通读关于 Behaviors .

    如果你现在喜欢Propel,你会的 之后!

    要解决您的问题,请查看 NestedSet Behavior 。与所有其他行为一样,很容易将其添加到您的模式中。重新生成模型,您只需要对代码进行小的重构(示例将向您展示如何重构)。

    (注意:如果您有一个现有的数据库,您将需要将父链接迁移到嵌套的集合结构。但这基本上是您应该关心的唯一问题。)

    中提供了显示整个树的示例 Using a RecursiveIterator 部分