在Doctrine 2中填写所有相关实体的部分集合

时间:2013-03-23 15:13:57

标签: php doctrine-orm doctrine

假设我有以下查询返回一个User实体,其中包含已标记的关联Post实体(这仅用于演示):

SELECT u, p
FROM User u
LEFT JOIN u.posts p
WHERE p.isFlagged = true

一旦我使用了这个,我就想访问该用户的所有帖子,无论isFlagged如何。有没有一种简单的方法来刷新$user->posts集合,以便它是所有用户帖子的完整集合?

我不想只删除查询中的所有帖子(因为可能不需要),并且需要完整集合的代码不会意识到该实体来自的查询。

3 个答案:

答案 0 :(得分:1)

你在这里做的事情已经破裂了:

SELECT
    u, p
FROM
    User u
JOIN
    u.posts p
    WITH
    p.isFlagged = true

这将使用错误的值来保存`User#posts'集合,这会导致逻辑损坏,对象图破坏,一切都被破坏。

您应该在DQL级别解决此问题,如下所示:

SELECT
    u, p
FROM
    User u
JOIN
    u.posts p
JOIN
    u.posts j
    WITH
    j.isFlagged = true

这基本上会在用户对象中保留正确的帖子集合,而没有任何中间(破坏)状态。

编辑 :我误解了这个问题,因为我的想法是基于@Athlan的答案,这根本就是错误的(冲破破碎的集合确实是错误的)。这是我之前的回答,我仍然认为它很有趣,因为它解决了这个问题,但并没有以一种非常正确的方式解决。

这个问题实际上让我很好奇,看看ORM是否按照我的预期更新了收藏品。

wrote the test in this branch

基本上,您需要做的只是:

$entityManager->refresh($entity);

以下是测试的相关部分:

$foo = new DDC2666Foo();

$this->_em->persist($foo);
$this->_em->flush();
$this->_em->clear();

$fetchedFoo = $this->_em->find(__NAMESPACE__ . '\DDC2666Foo', $foo->id);

$fetchedFoo->bars->add(new DDC2666Bar());

$this->assertCount(1, $fetchedFoo->bars);
$this->_em->refresh($fetchedFoo);

$this->assertCount(0, $fetchedFoo->bars, 'The collection was reset');

缺点是这也会重新获取您的实体,但ORM本身并不提供刷新单个集合的外观。

无论如何,这也是一件好事,因为这样,你不会破坏封装,这可能会导致代码中的意外(并且难以调试)行为。

答案 1 :(得分:0)

我有同样的问题,最后到此为止。刷新不是我的选择,因为我有一个列表,我不想进行额外的查询。

这里你真正需要的是添加一个“假”连接来进行过滤,并保留原始连接没有条件......以明确这一点:

SELECT u, p
FROM User u
LEFT JOIN u.posts p
LEFT JOIN u.posts p2
WHERE p2.isFlagged = true

请注意,我将从select子句中删除p2,它仅用于过滤目的。

答案 2 :(得分:0)

我发现其他解决方案非常不令人满意,因为许多实体将变得水土不服,而我根本不感兴趣。如果绝大多数职位都isFlagged = 0,那么对性能的影响是巨大的。

这是一个替代解决方案,涉及围绕实体之间的关系交换。但是,它与原始问题不完全等同。但是对于其他遇到此问题的人可能有用:

SELECT p, u
FROM Post p
JOIN p.user u
WHERE p.isFlagged = true

此解决方案与其他解决方案之间的区别在于,它将不再返回没有任何帖子或未标记任何帖子的用户。这可能是您想要的,也可能不是。