Activerecord Yii2中的线程数据

Activerecord Yii2中的线程数据,activerecord,yii2,hierarchical-data,Activerecord,Yii2,Hierarchical Data,我正在寻找一种解决方案,通过活动记录在单个查询中获取分层数据 我现在做的是首先获取所有数据,然后使用递归函数将数组转换为所需的数组 $allUsers = User::find() ->asArray() ->all(); $arr = Yii::$app->TreeComponent->getUserChildren($allUsers, $userId, $userId); 和在树组件中 public function getUser

我正在寻找一种解决方案,通过
活动记录
在单个查询中获取分层数据

我现在做的是首先获取所有数据,然后使用递归函数将数组转换为所需的数组

$allUsers = User::find()
        ->asArray()
        ->all();
$arr = Yii::$app->TreeComponent->getUserChildren($allUsers, $userId, $userId);
和在树组件中

public function getUserChildren($src_arr, $currentId, $userId, $parentFound = false)
{
    $cats = array();
    foreach ($src_arr as $row) {
        if ($row['id'] == $userId) {
            $row['parent'] = "";
        }
        if ((!$parentFound && $row['id'] == $currentId) || $row['parent'] == $currentId) {
            $rowData = array();
            foreach ($row as $k => $v)
                $rowData[$k] = $v;
            $cats[] = $rowData;
            if ($row['parent'] == $currentId) {
                $cats = array_merge($cats, $this->fetchRecursive($src_arr, $row['id'], true));
            }
        }
    }
    return $cats;
}
工作正常。但最近我通过了,我认为它将节省递归函数的执行时间和更少的代码


我很好奇是否也有任何函数存在

在Yii2中没有这样的功能。CakePHP还将在后台执行多个查询,并将其封装在多线程调用中。如果您实际上只能执行一个查询,那么您将获得主要的速度优势

有两种方法可以实现这一点:

  • 您的方式…获取所有内容并将其合并到代码中
  • 上述注释中提到的嵌套集模式
嵌套集

对于Yii2,有一个很好的扩展来实现嵌套集模式。你可以在这里找到它:

优点和缺点

很明显,它的优点是您可以通过一个查询获取所有内容。您甚至可以在一个表中保存多棵树

主要缺点是根据列进行排序,同时仍然保持树结构。嵌套集由两个属性组织:左属性和右属性。这意味着,所有数据都根据这两个属性进行排序。要获取按名称排序的树结构,仍然需要实现代码端功能,以便在查询后更改接收到的数据集。最干净的方法是在保存时对数据进行排序…这意味着根据其在所需排序中的位置插入新记录

Wikipedia对嵌套集有很好的解释:

此图显示了其工作原理:

例如:“宽松裤”和“夹克衫”是“西装”的子项,因为它们的左右属性都在“西装”的左(3)和右(8)值之间。如果你想在“夹克”中添加一个子元素,你可以在6到7之间注入它……因此,将所有大于或等于7的值都增加2。然后,新注入的“夹克”子对象将收到左值7和右值8

如您所见,现在只需过滤左属性和右属性即可轻松获取整个(子)树。如果您想要从“西装”到其他任何东西,您的查询将如下所示:

SELECT * FROM mytable WHERE left >= 3 AND right <= 8 ORDER BY left ASC

SELECT*FROM mytable,其中left>=3,right这里是另一种存储树并获取它的方法,无需递归。它需要两张桌子

tree_data

  Column   |  Type   |                                         
-----------+---------+
 id        | integer | 
 parent_id | integer |
 level     | integer |
 sort      | integer | 


tree_structure

 Column |  Type   |                          
--------+---------+
 parent | integer |
 child  | integer |
例如:

select * from tree_data;

 id | parent_id | level | sort 
----+-----------+-------+------
  1 |         0 |     0 | 1000
  2 |         1 |     1 | 1000
  3 |         1 |     1 | 2000
  4 |         1 |     1 | 1500
  5 |         1 |     1 | 1750
  6 |         5 |     2 | 1000


select * from tree_structure order by parent, child;

 parent | child 
--------+-------
      1 |     1
      1 |     2
      1 |     3
      1 |     4
      1 |     5
      1 |     6
      2 |     2
      3 |     3
      4 |     4
      5 |     5
      5 |     6
      6 |     6
生成的树:

├── 1
│   ├── 2
│   ├── 4
│   ├── 5
│       ├── 6
│   ├── 3
要查询树,请执行以下操作:

SELECT tree_data.* 
FROM tree_data
INNER JOIN tree_structure ON tree_data.id = tree_structure.child and tree_structure.parent = 1 
ORDER BY level, sort;

这里有一组类用于

没有函数用于此,但您可能需要使用。Yii的AR不能在一次调用中填充层次结构数据。可以使用引用构建树状数组结构,以避免递归。如果你对此感兴趣,我可以发布一个例子。@nineinchnick是的,请让我看看这个例子。快速搜索一下就会发现。这一个看起来排序很重要,所以我要添加一个
isset
检查。谢谢@PLM57的回答。我主要关心的是速度,因为有成千上万的记录。在我的例子中,一个节点可以有两个以上的子节点,如果嵌套集仍然是有效的方法?欢迎!是的,每个节点可以有任意多个子节点!它不像二叉树那样只允许两个子树…它是一个常规树,但组织方式不同(使用左/右属性而不是父ID)。wiki文章中的这幅插图很好地解释了这一点: