当前位置: 首页 > 知识库问答 >
问题:

Pomm项目中具有水合模型的树结构

匡凌
2023-03-14

我有一个简单的数据库表,它通过parent_id属性实现树结构。

+----+------+-----------+
| id | name | parent_id |
+----+------+-----------+
|  1 | test | null      |
+----+------+-----------+
|  2 | tes2 | 1         |
+----+------+-----------+
|  3 | tes3 | 2         |
+----+------+-----------+
|  4 | tst  | 2         |
+----+------+-----------+

我想获得具有树结构的PHP对象。因此,对象类别将具有属性子类别,即类别对象列表等。我希望通过Pomm的递归sql查询直接从PostgreSQL数据库中获取此对象。目标不是遍历获得的数据并在PHP中构建这样的对象。我想要直接处理PostreSQL-

至于现在,我只在第一级就得到了我想要的。所以第一级类别有子类别,即类别实体列表。但是,下一个级别(深度2)没有子类别。

到目前为止,我有:

$sql = <<<SQL
with recursive
cat as (select c.* FROM :category c where parent_id is null),
subcat as (
select c.* from :category c join cat on c.parent_id=cat.id
union all
select c.* from :category c join subcat on c.parent_id=subcat.id
)
select :projection from cat cc, subcat
where cc.id=subcat.parent_id
group by :group_fields
SQL;

$projection = $this->createProjection()
    ->setField('subcategories', 'array_agg(subcat)', 'public.category[]');
$sql = strtr($sql, [
        ':category' => $this->structure->getRelation(),
        ':projection' => $projection->formatFieldsWithFieldAlias('cc'),
        ':group_fields' => $this->createProjection()->formatFields('cc'),
]);

我的问题是,这在Pomm中是否可行,如果可行,如何实现?

共有1个答案

傅毅然
2023-03-14

您想要直接实现的并不是真正可能的,因为在Pomm中,出于性能原因,当执行查询时,迭代器将数据库游标包装在结果上。

$iterator = $this->query($sql, $array_of_parameters);

foreach ($iterator as $entity) {
   $entity->getParentId();
}

每次从迭代器中提取数据时,转换器系统都会将其转换为实体。但实体不了解数据库,因此无法使用其访问器获取更多数据。

一个简单的想法是获取一个结果,其中包含作为嵌套实体的所有结果:

with recursive
cat as (
select * from test_tree tt where not exists (select parent_id from test_tree tt2 where tt2.parent_id = tt.id)
union all
select tt.*, array_agg(child) from test_tree tt join cat child on tt.id = child.parent_id group by tt.id
)
select * from cat

但不幸的是,在CTE的递归项中不可能使用聚合函数。

另一个想法是索引id上的结果,为每个parent_id提供子级,并使用Pomm迭代器可滚动来获取它们:

with
  tree as (
    select
      tt.id,
      array_agg(child) as children
    from
      test_tree tt
      join lateral (select * from test_tree tt2 where tt2.parent_id = tt.id) child on (true) group by tt.id
  )
select
  idx as id,
  tree.children
from
  generate_series(1, (select max(id) from test_tree)) idx
  left join tree on tree.id = idx

哪些输出:

┌────┬─────────────────────────────────────────┐
│ id │                children                 │
├────┼─────────────────────────────────────────┤
│  1 │ {"(2,\"test 2\",1)","(3,\"test 3\",1)"} │
│  2 │ {"(4,\"test 4\",2)","(5,\"test 5\",2)"} │
│  3 │ {"(6,\"test 6\",3)"}                    │
│  4 │ ¤                                       │
│  5 │ ¤                                       │
│  6 │ {"(7,\"test 7\",6)"}                    │
│  7 │ ¤                                       │
└────┴─────────────────────────────────────────┘
(7 rows)

然后,结果集将按parent\u id so$迭代器排序-

从另一方面考虑这个问题,似乎可以创建专用的灵活实体,在内部嵌入嵌套集设计模式以在子级上递归。

 类似资料:
  • 在树结构的目录系统中,任何目录条目都可以是文件或子目录。 树结构的目录系统克服了两级目录系统的缺点。 现在可以将类似的文件分组到一个目录中。 每个用户都有自己的目录,并且不能进入其他用户的目录。 但是,用户有权读取根数据,但他不能写入或修改此数据。 只有系统管理员才能完全访问根目录。 在这个目录结构中搜索更有效率。 使用当前工作目录的概念。 一个文件可以通过两种类型的路径访问,无论是相对的还是绝对

  • 好吧,我就直接说吧。我有一个使用Spring的多模块maven项目。项目结构可概括如下: 在本例中,根级pom文件将spring-boot-starter声明为父级: > 我可以分离出依赖项,以便模块1和模块2将spring-boot-starter-parent作为它们的父项,并从根pom中删除spring-boot-starter,从而释放common。 我可以将根pom作为父级删除到Comm

  • 我在项目中有两个模块(和)运行集成测试。我希望在测试之前,我的应用程序将使用liquibase启动和滚动迁移,但由于我通过集成测试模块运行应用程序,liquibase正在寻找一个关于该模块的主文件,该文件导致了错误。因为主文件位于miom应用程序()的模块中

  • 新加入WPF的我正尝试使用TreeView,它提供的灵活性给我留下了难以置信的印象。 到目前为止,我的每个treeview项目都实现了一个扩展器,这是显示每个项目更详细信息并让标题仅显示摘要的好方法。但是,这不适合叶项目,并且浪费了屏幕空间——我的treeview中的每个叶项目(其中有许多)显示的数据量相对较小。 我想要为叶项目实现的是水平包装,而不是垂直列表。设想显示一个网格或(stackpan

  • 比如一辆车,在Threejs中你可以使用一个网格模型去描述车上面的一个零件,多个零件就需要多个网格模型表示,这些网格模型之间就会构成父子或兄弟关系,从而形成一个层级结构。在机械、建筑相关的Web3D应用中,通常会用到层级模型的知识,一个层级模型就是一本书的目录一样。 本章主要目的是帮助你建立Threejs层级模型的概念,通过Threejs的组对象Group可以组织各个模型,构成一个层级结构。学习本