【问题标题】:Doctrine QueryBuilder indexBy on joined class - p is already defined ErrorDoctrine QueryBuilder indexBy on join class - p 已定义错误
【发布时间】:2015-07-01 21:11:11
【问题描述】:

使用 symfony2/doctrine2,我很难为我的查询定义索引。

我的代码:

    $queryBuilder = $this->_em
        ->createQueryBuilder()
        ->select('u, uis, cost, p, stock')
        ->from('AppBundle:FoodAnalytics\UserIngredient', 'u', 'p.id')
        ->leftJoin('u.product', 'p')
        ->leftJoin('u.numberObjects', 'stock')
        ->leftJoin('u.userIngredientSuppliers', 'uis')
        ->leftJoin('uis.numberObjects', 'cost')
        ->where('u.user = ?1')
        ->setParameter(1, $portfolioUser)
        ;

我收到以下错误:

[Semantical Error] line 0, col 110 near 'p LEFT JOIN u.numberObjects': Error: 'p' is already defined.
500 Internal Server Error - QueryException
1 linked Exception: QueryException »

[1/2] QueryException: SELECT u, uis, cost, p, stock FROM AppBundle:FoodAnalytics\UserIngredient u INDEX BY p.id LEFT JOIN u.product p LEFT JOIN u.numberObjects stock LEFT JOIN u.userIngredientSuppliers uis LEFT JOIN uis.numberObjects cost WHERE u.user = ?1   +

使用u.product 我得到以下错误:

[Semantical Error] line 0, col 87 near 'product LEFT': Error: Invalid PathExpression. Must be a StateFieldPathExpression.
500 Internal Server Error - QueryException
1 linked Exception: QueryException »

仅使用 product,我收到以下错误:

[Semantical Error] line 0, col 85 near 'product LEFT': Error: 'product' does not point to a Class.
500 Internal Server Error - QueryException
1 linked Exception: QueryException »

如果我使用u.id,它可以正常工作 我只能按同一张表中的字段使用索引吗?

我该怎么做才能让它发挥作用?

非常感谢!

编辑:

作为临时修复我正在使用:

    $result = $queryBuilder->getQuery()->getResult();
    $result = array_combine(array_map(function(UserIngredient $userIngredient){
                return $userIngredient->getProduct()->getId();
            }, $result), $result);
    return $result;

【问题讨论】:

  • 我不确定您是否可以使用相关实体的字段来索引实体。
  • 我可能完全错了,但您可以尝试使用 product.id 而不是 p.id 进行索引。另外,这个:doctrine-project.org/jira/browse/DDC-1180
  • 好的,product.id 不起作用。但是,您的参考表明已实施修复,但我尚未找到相应的解决方案。你有吗?
  • 根据 PR,这可以工作:-from('AppBundle:FoodAnalytics\UserIngredient', 'u', 'product')。是吗?
  • 指定索引的目标是从product表开始,然后加入UserIngredient表吗?如果 Product.Id 是主键,你可以从 Product 开始,不需要指定索引,然后与 UserIngredient 进行左连接。

标签: php mysql symfony doctrine-orm query-builder


【解决方案1】:

属性indexBy 仅适用于您当前选择的实体,正如您所猜测的(和 AFAIK);所以在你的情况下,你只能按u.id索引。

这对我来说很有意义,因为来自其他实体的索引确实会弄乱返回的结果。获得正确结果的唯一情况是:

  • 所有来自主实体和“目标”indexBy 实体的连接都是一对一的;
  • 所有的join都是INNER JOIN;
  • 结果集的 indexBy 列是唯一的。

在其他情况下,您在水合期间会丢失一些实例引用。

在您的示例中,您使用的是 LEFT JOIN:没有产品的所有实体会发生什么情况?全部丢弃,所以 LEFT JOIN 会有像 INNER JOIN 这样的工人。此外,您的解决方法建议您要组合具有相同索引的实体,但这不是 Doctrine 的工作方式:在 Doctrine 中, indexBy 列必须是唯一的。请参阅the official docs 了解更多信息。

请注意,您可以在 JOIN 子句中使用 indexBy p.id,但这具有不同的含义。这意味着在对 UserIngredients 实例进行水合时,产品的集合应按 id 进行索引。

所以,我的建议是遵循以下两种解决方案之一:

  • 放弃 Doctrine indexBy,使用您的解决方法;
  • 如果您有反向关联Product -> UserIngredients,则使用Product 作为查询的主要实体(from 子句,并首先出现在select 中),然后按p.id 进行索引。

使用哪个取决于你的业务逻辑,但我一般更喜欢第二种解决方案,因为第一种生成多级数组,用实体关系更好地表示。

希望对您有所帮助! :)

【讨论】:

  • 嗯,确实很有趣!在我的情况下,我有一个独特的约束,可以保证每个产品和用户不超过一个用户成分,所以我们需要索引,就好像我们有一个 OneToOne 关系,但事实并非如此。鉴于 PR Jovan 谈到的,我想我们期望它可以完成是正确的......仍在寻找更好的解决方案
  • 我认为 DDC-1180 与您的问题无关。这是关于“实体的列也是外键”,所以我的考虑仍然适用于这种情况。事实上,该问题已在 Doctrine 2.1 中修复并合并,您现在可以使用它。
  • (oops clicked enter too fast) 还要考虑即使它可以完成(但我认为它不会,由于许多前提条件),它仍然不适用于你的情况,因为leftJoin 破坏了您的逻辑,因为您不能将多个值绑定到null-key 条目。
猜你喜欢
  • 2012-02-14
  • 1970-01-01
  • 2017-06-02
  • 2022-11-03
  • 2018-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多