【问题标题】:Symfony/Doctrine relation COUNT in entity实体中的 Symfony/Doctrine 关系 COUNT
【发布时间】:2016-02-02 18:20:05
【问题描述】:

如标题所述,

我想运行 1 个查询以从表中获取结果以及它们各自的关系计数。

假设我有一个Person 实体与一个Friend 实体具有OneToMany 关系

Person 实体可能如下所示:

class Person
{
    /**
     * @ORM\OneToMany(...)
     */
    protected $friends;

    public function __construct()
    {
        $this->friends = new ArrayCollection();
    }

    ...
}

我想要实现的经典 SQL 解决方案可能如下所示:

SELECT p.*, COUNT(f.id) as friendsCount
FROM Persons p
LEFT JOIN Friends f
ON f.person_id = p.id
GROUP BY p.id

现在我想知道这是否也可以在 DQL 中完成并将 count 值存储到 Person 实体中

假设我扩展 Person 实体,例如:(请记住,这只是一个想法)

class Person
{
    /**
     * @ORM\OneToMany(...)
     */
    protected $friends;

    protected $friendsCount;

    public method __construct()
    {
        $this->friends = new ArrayCollection();
    }

    ...

    public function getFriendsCount()
    {
        return $this->friendsCount;
    }
}

现在我无法找到如何从 DQL 填充实体中的计数值:

SELECT p, /* What comes here ? */
FROM AppBundle\Entity\Person p
LEFT JOIN p.friends f
GROUP BY p.id

PS:我知道我可以这样做:

$person->getFriends()->count();

甚至将其标记为额外懒惰以获取计数结果。

尽管这个 count 关系 示例很好地展示了我正在尝试做的事情。

(从 dql 填充实体的非 @ORM\Column 属性)

Doctrine 可以做到这一点吗?

这是否违反了一些可靠的原则? (建议零售价?)

你的想法的 Cookie ;)

【问题讨论】:

    标签: symfony doctrine-orm count entity relationship


    【解决方案1】:

    您可能只想根据需要选择计数,如上文$person->getFriends()->count(); 所述。但是,您可以同时选择一个对象和一个计数 - 请参阅这些 Doctrine DQL examples,其中一个与您正在做的非常相似:

    SELECT p, COUNT(p.friends)
    FROM AppBundle\Entity\Person p
    LEFT JOIN p.friends f
    GROUP BY p.id
    

    应该返回一个包含对象和计数的数组,如下所示:

    [
        [Person, int],
        [Person, int],
        ...,
    ]
    

    最好的办法是在 PersonRepository 上调用存储库,类似于 findPersonsWithFriendCount(),如下所示:

    public function findPersonsWithFriendCount()
    {
        $persons = array();
    
        $query = $this->_em->createQuery('
            SELECT p, COUNT(p.friends)
            FROM AppBundle\Entity\Person p
            LEFT JOIN p.friends f
            GROUP BY p.id
        ');
    
        $results = $query->getResult();
    
        foreach ($results as $result) {
            $person = $result[0];
            $person->setFriendsCount($result[1]);
    
            $persons[] = $person;
        }
    
        return $persons;
    }
    

    请记住,您需要在您的 Person 对象上添加一个 setFriendsCount() 函数。您还可以编写原生 SQL 查询并使用 result set mapping 自动将原始结果的列映射到实体字段。

    【讨论】:

    • 非常感谢这个例子!真的很有帮助
    • 请记住,这不是必需的。如果您只是像这样明确地加入存储库调用,您可以像往常一样删除COUNT() 并返回实体,然后将return $this->friends->count() 放入您的getFriendsCount() 方法中。如果您明确加入,它不会添加另一个数据库调用...如果您还没有加载它们,它会。
    • 确实不错,我什至可能不需要明确需要 getFriendsCount() 并在加入后需要它的地方使用 getFriends()->count() 。但是这种技术可能对一些特殊的查询有用。你对(非常)大量的关系和表现有什么想法。加入(并因此补充)大量实体只是为了获得计数可能会减慢速度。只是大声思考(写作):)
    • 我通常的工作方式是首先使用 ORM 和最简单的方式......然后如果有性能问题,开始查看原始查询,删除水合作用,缓存等。我尽量不要进行过多的预优化,除非它像使用连接来防止页面运行 50 个额外的查询或类似的东西。
    • 我必须将原始查询更新为此 SELECT p, COUNT(f) ... 才能使其正常工作。
    猜你喜欢
    • 2016-12-05
    • 2017-02-27
    • 1970-01-01
    • 2013-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多