【问题标题】:Doctrine query works with SQLite, not with MySQLDoctrine 查询适用于 SQLite,而不适用于 MySQL
【发布时间】:2018-04-14 15:59:49
【问题描述】:

我使用 Doctrine (doctrine/orm v2.6.1) 和 Symfony 创建了两个名为 Project 和 ProjectTag 的实体。我想选择所有标签都带有$tags 中给出的名称的所有项目。我的ProjectRepository.php 中的以下查询在我的开发环境中使用 SQLite:

public function findByAllTags($tags)
{
    $queryBuilder = $this->createQueryBuilder('p');
    for ($i = 0; $i < count($tags); $i++) {
        $tagSubQueryBuilder = $this->createQueryBuilder("p$i")
            ->join('p.tags', "tags_joined_$i")
            ->andWhere("tags_joined_$i.name = ?$i");
        $queryBuilder->andWhere(
            $queryBuilder->expr()->exists($tagSubQueryBuilder->getDQL())
        );
    }
    $queryBuilder->orderBy('p.timeCreated','DESC');
    return $queryBuilder->getQuery()->setParameters($tags)->getResult();
}

这被转换为

SELECT 
  p0_.id AS id_0, 
  p0_.name AS name_1
FROM 
  project p0_ 
WHERE 
  (
    EXISTS (
      SELECT 
        p1_.id 
      FROM 
        project p1_ 
        INNER JOIN projects_tags p3_ ON p0_.id = p3_.project_id 
        INNER JOIN project_tag p2_ ON p2_.id = p3_.project_tag_id 
      WHERE 
        p2_.name = ?
    )
  ) 
ORDER BY 
  p0_.created DESC

但是,在我使用 MySQL 的生产环境中,我收到以下错误:

An exception occurred while executing 'SELECT p0_.id AS id_0, p0_.name AS name_1 FROM project p0_ WHERE (EXISTS (SELECT p1_.id FROM project p1_ INNER JOIN projects_tags p3_ ON p0_.id = p3_.project_id INNER JOIN project_tag p2_ ON p2_.id = p3_.project_tag_id WHERE p2_.name = ?)) ORDER BY p0_.created DESC' with params ["video"]:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'p0_.id' in 'on clause'

【问题讨论】:

  • 这看起来有点混乱,那个查询应该返回什么?
  • 查询应该(和 SQLite 一样)返回项目的项目 ID 和名称(在这种情况下是id_0name_1),这些项目的所有标签都带有数组 @987654328 中的名称@。在我发布的自动转换为 SQL 的情况下,$tags 仅包含一个元素,因此只有一个 EXISTS 子句。我使用@ORM/ManyToMany 为项目分配标签,反之亦然:@ORM\ManyToMany(targetEntity="App\Entity\ProjectTag", inversedBy="projects") \n @ORM\JoinTable(name="projects_tags") 这个连接表是上面的内部连接中使用的
  • 您的嵌套查询选择了project p1_,而没有任何连接条件引用它。为什么不在单个非嵌套查询中内部连接标签表并跳过 EXISTS
  • 你能举个简短的例子吗?例如,我不确定这将如何让我选择同时具有“视频”和“图片”标签的项目。

标签: symfony doctrine-orm


【解决方案1】:

针对您的评论,这是一种未经测试的解决您问题的方法,无需嵌套查询:

public function findAllByTags($tags)
{
    $qb = $this->createQueryBuilder('p');

    $qb->join('p.tags', 't');
    $qb->where($qb->expr()->in('t.name', ':tags'));
    $qb->groupBy('p.id');
    $qb->having($qb->expr()->eq('COUNT(t.id)', ':count'));

    $qb->setParameter('tags', $tags);
    $qb->setParameter('count', count($tags));

    return $qb->getQuery()->getResult();
}

这假设您将标签名称作为数组传递(或者Tag 类实现了返回标签名称的__toString() 方法)。

【讨论】:

  • 这很好用,谢谢!我忘记了 groupBy 的存在和用处,如果需要,count 参数可以很容易地将合取变成析取。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-12
  • 2011-12-24
  • 1970-01-01
  • 1970-01-01
  • 2014-04-24
  • 1970-01-01
  • 2020-08-23
相关资源
最近更新 更多