【问题标题】:Tree structure with hydrated model in Pomm-projectPomm 项目中具有水合模型的树结构
【发布时间】:2015-10-10 23:50:29
【问题描述】:

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

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

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

就目前而言,我只能在第一级得到我想要的。所以第一级类别有子类别,这是类别实体的列表。但是下一级(深度 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 是否可以实现,如果可以,如何实现?

【问题讨论】:

    标签: php postgresql pomm


    【解决方案1】:

    您想要实现的目标实际上并不能直接实现,因为在 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_id 排序,因此 $iterator-&gt;get($parent_id) 将返回一个子实体数组(或 null),但这看起来更像是一种 hack 而不是真正的功能。

    从另一端解决问题,似乎可以创建专用的灵活实体 embed a nested set design pattern 在内部递归子级。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-06-16
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 2020-09-06
      • 1970-01-01
      相关资源
      最近更新 更多