查询生成器或闭包或 DQL,这是使用多对多关系处理此复杂 SQL 查询的正确选择



所以我有两个实体:

class TipoRegistro
{
    /**
     * @ORMManyToMany(targetEntity="AppBundleEntityTipoTramite", inversedBy="tipoRegistros", cascade={"persist"})
     * @ORMJoinTable(name="nomencladores.tipo_registro_tipo_tramite", schema="nomencladores",
     *      joinColumns={@ORMJoinColumn(name="tipo_registro_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORMJoinColumn(name="tipo_tramite_id", referencedColumnName="id")}
     * )
     */
    protected $tipoTramites;
}
class TipoTramite
{
    /**
     * @ORMManyToMany(targetEntity="AppBundleEntityTipoRegistro", mappedBy="tipoTramites", cascade={"persist"})
     */
    protected $tipoRegistros;
}

我需要获取与 trhough ManyToMany 关系相关的所有TipoRegistro TipoTramite如前所示,如下面的 SQL 所示:

SELECT tr.* 
FROM
    nomencladores.tipo_registro tr
LEFT JOIN
    nomencladores.tipo_registro_tipo_tramite AS trtt
ON (trtt.tipo_registro_id = tr."id")
WHERE
    tr.activo = true
AND
    trtt.tipo_tramite_id = 1;

我不知道我是否可以在这里使用自定义存储库,所以我唯一的解决方案是在表单级别使用query_builder参数,这就是我正在做的事情:

'query_builder' => function (EntityRepository $er) {
    return $er->createQueryBuilder('tr')
        ->where('tr.activo = :activo')
        ->leftJoin('tr.tipoTramites', 'ttr')
        ->andWhere("ttr.tipo_tramite_id  = :tramite")
        ->setParameter("tramite", 1)
        ->setParameter('activo', true);
}

但该解决方案会导致此错误:

[语义错误] 第 0 行,第 121 行靠近"tipo_tramite_id":错误: 类 AppBundle\Entity\TipoTramite 没有字段或 名为tipo_tramite_id的协会

我也尝试了这个(按照此处每个用户的建议):

->andWhere("ttr.tipoTramites  = :tramite")

但是错误变成了这个:

[语义错误] 第 0 行,第 120 行,靠近"tipoTramites":错误:无效 路径表达式。StateFieldPathExpression 或 单值关联预期字段

我也尝试了其他解决方案:

->andWhere("tr.id = :tramite")

但是这个不会返回正确的值。我阅读了一些有关实体字段类型的Closures,但不知道如何在这种情况下实现。我想到的另一个想法是使用 DQL 和准备语句,但我瘦了,这不能在表单级别使用,所以我没有想法,那么我如何获得这些值?我应该如何建立这个多对多实体之间的关系?

当您在实体中创建 ManyToMany 关系时,Doctrine 将生成第三个表作为这两个实体(在 @ORMJoinTable 中命名)之间的中介,其中包含两个字段(在 joinColumns 中定义)。您不能直接访问第三个表中的字段或列,但它们都将由 DQL 中的 Doctrine 处理。
这意味着在DQL中,您只需在where子句中设置联合表ID,而不是真正的字段名称,Doctrine将生成正确的SQL:

'query_builder' => function (EntityRepository $er) {
   return $er->createQueryBuilder('tr')
     ->where('tr.activo = :activo')
     ->leftJoin('tr.tipoTramites', 'ttr')
     ->andWhere("ttr.id  = :tramite")
     ->setParameter("tramite", 1)
     ->setParameter('activo', true);
}

这将生成正确的 SQL。
唯一的提示是你无权访问DQL中第三个表的生成字段,但它将由Doctrine处理,你可以使用连接表id代替

最新更新