假设我有以下查询返回一个User实体,其中包含已标记的关联Post实体(这仅用于演示):
SELECT u, p
FROM User u
LEFT JOIN u.posts p
WHERE p.isFlagged = true
一旦我使用了这个,我就想访问该用户的所有帖子,无论isFlagged如何。有没有一种简单的方法来刷新$user->posts
集合,以便它是所有用户帖子的完整集合?
我不想只删除查询中的所有帖子(因为可能不需要),并且需要完整集合的代码不会意识到该实体来自的查询。
答案 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
此解决方案与其他解决方案之间的区别在于,它将不再返回没有任何帖子或未标记任何帖子的用户。这可能是您想要的,也可能不是。