如何在Symfony Doctrine中使用QueryBuilder在两个实体之间JOIN而无需关系表

6

我有一个与实体类别相关的实体视频,我需要使用Doctrine QueryBuilder运行此SQL语句,通过这个可以获取所有视频中最常用的类别(1000+):

    SELECT c.*
    FROM Video v
    INNER JOIN video_category vc ON vc.video_id = v.id
    INNER JOIN Category c ON vc.category_id = c.id
    GROUP BY c.id
    HAVING COUNT(v.id) > 1000
    ORDER BY c.name ASC;

我的查询构建器:

    $queryBuilder = $this->getEntityManager()
        ->createQueryBuilder()
        ->select('c')
        ->from('AcmeVideoBundle:Video', 'v')
        // Can Doctrine join itself silently with relational info in the Entities?
        ->join('AcmeCategoryBundle:Category', 'c', Expr\Join::WITH, 'v.id = c.id')
        ->groupBy('c.id')
        ->having('COUNT(v.id) > 1000')
        ->orderBy('c.name', 'ASC')
        ->getQuery();

但是queryBuilder输出的SQL查询是这样的:
    SELECT c0_.id AS id0, c0_.NAME AS name1 
    FROM Video v1_ 
    INNER JOIN Category c0_ ON (v1_.id = c0_.id) 
    GROUP BY c0_.id 
    HAVING COUNT(v1_.id) > 1000
    ORDER BY c0_.NAME ASC

没有关系表(video_category)

实体映射:

    /**
     * Video
     *
     * @ORM\Table
     * @ORM\Entity(repositoryClass="Acme\VideoBundle\Entity\VideoRepository")
     */
    class Video
    {
        /**
         * @ORM\Id
         * @ORM\Column(type="integer")
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        private $id;

        /**
         * @ORM\ManyToMany(targetEntity="Acme\CategoryBundle\Entity\Category", cascade={"persist"})
         */
        private $category;

        // More fields, getters and setters etc...
    }

    /**
     * Category
     *
     * @ORM\Table
     * @ORM\Entity(repositoryClass="Acme\CategoryBundle\Entity\CategoryRepository")
     */
    class Category
    {
        /**
         * @ORM\Id
         * @ORM\Column(type="integer")
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        private $id;

        /**
         * @ORM\Column(type="string", length=255)
         */
        private $name;

        // More fields, getters and setters etc...
    }

如何使用关联表在Doctrine Querybuilder中运行原始SQL查询?我漏掉了什么?
信息:当我使用findBy{field},persist,flush和clear时,所有实体都可以正常工作,Doctrine关系也正确,我有一个Video,Category和video_category表,原始的SQL查询完美地工作。

你是否尝试像使用JOIN一样声明关联表? - Thomas Potaire
是的:[语义错误]第0行,第54列附近的'video_category':错误:未定义类'video_category'。 - Tecnocat
2个回答

15
   // Can Doctrine join itself silently with relational info in the Entities?
    ->join('AcmeCategoryBundle:Category', 'c', Expr\Join::WITH, 'v.id = c.id')
是的!事实上这是使用ORM(例如Doctrine 2)的主要原因之一。
尝试:
->leftJoin('v.category','c')

手册提供了更详细的信息,但奇怪的是它似乎没有一个联接示例,因此常常会引起困惑。

http://docs.doctrine-project.org/en/latest/reference/query-builder.html

也许你不知道,联合国已通过一项决议,禁止使用缩写作为别名。为了安全起见,请尝试:

$queryBuilder = $this->getEntityManager()
    ->createQueryBuilder()
    ->addSelect('category')
    ->from('AcmeVideoBundle:Video', 'video')
    ->leftJoin('video.category', 'category')
    ->groupBy('category.id')
    ->having('COUNT(video.id) > 1000')
    ->orderBy('category.name', 'ASC')
    ->getQuery();

我喜欢使用全名作为别名,但在StackOverflow的示例中,我使用了缩写来澄清。这样做可以让有相同观点的人更容易理解!在过去几个小时中,我遇到了与其他->select()和->join() / innerJoin()组合相同的异常:[语义错误]第0行,第-1列附近的“SELECT category”:错误:不能通过标识变量选择实体而不选择至少一个根实体别名。我使用了你提供的代码 :/ - Tecnocat

-1

好的,问题解决了,问题在于双向ManyToMany关系的实体没有完全映射。

现在的实体为:

    class Video
    {
        /**
         * @var ArrayCollection
         *
         * @ORM\ManyToMany(targetEntity="Acme\CategoryBundle\Entity\Category", inversedBy="video") // Note the inversedBy key
         */
        private $category;
    }

    class Category
    {
        /**
         * @var Video
         *
         * @ORM\ManyToMany(targetEntity="Acme\VideoBundle\Entity\Video", mappedBy="category") // Again the inversed
         */
        private $video; // New field for bidirectional ManyToMany
    }

最终的 QueryBuilder 工作正常(现在带有完整的别名版本 :P):

    $queryBuilder = $this->getEntityManager()
        ->createQueryBuilder()
        ->select('category')
        ->from('AcmeCategoryBundle:Category', 'category')
        ->join('category.video', 'video')
        ->groupBy('category.id')
        ->having('COUNT(video.id) > 1000')
        ->orderBy('category.name', 'ASC')
        ->getQuery();

此致敬礼


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接