3

这是一个假设性的问题,因为我试图了解 Doctrine ORM 并且很难复制我在普通 SQL 中所做的事情。

假设我在标签和帖子之间有一个简单的多对多关系。他们将映射,因此这Post::tags是拥有方并且Tag::posts是反向映射。

我知道使用 Doctrine 的 DQL,我可以选择包含其标签的帖子,或使用以下 2 个查询引用其帖子的标签

(1)SELECT p, t FROM MyBundle:Post p JOIN p.tags t WHERE p.id = :id

(2)SELECT t, p FROM MyBundle:Tag t JOIN t.posts p WHERE t.id = :id

但是当我想通过多个标签获取帖子时,我必须在这些之间进行选择:

(3)SELECT p, t FROM MyBundle:Post p JOIN p.tags t WHERE t.value IN ('foo','bar')

(4)SELECT t, p FROM MyBundle:Tag t JOIN t.posts p WHERE t.value IN ('foo','bar')

这两个似乎都是错误的。

使用(3)我想数据库会先扫描整个帖子表,然后再将集合减少到标记的那些

使用(4)我得到了一组标签对象,这与我所追求的相反。

我尝试了以下方法,因为从逻辑上讲,它似乎反映了我在 SQL 中所做的事情:

SELECT p, pt FROM MyBundle:Tag t JOIN t.posts p JOIN p.tags pt
                 WHERE t.value IN ('foo','bar') GROUP BY p.id

它不起作用,因为 Doctrine 坚持我选择根实体

在标签上选择但将唯一帖子作为完整对象取回的最佳方法是什么?

4

1 回答 1

0

如果我很好地理解了这个问题,那么您想要的是选择所有至少有一个标签的值在定义的集合中的帖子(“foo”、“bar”、...)并忽略所有其他帖子。

让我们从(3)开始:

SELECT p, t FROM MyBundle:Post p JOIN p.tags t WHERE t.value IN ('foo','bar')

在 MySQL 中,这大约意味着:“选择所有标签为 foo 或 bar 的帖子”。

但是在 DQL 中,这意味着“选择所有帖子并仅附加值为 foo 或 bar 的标签”。这意味着查询将返回所有帖子的集合,但标签已过滤。这种行为差异是由于学说必须使用数据库层返回的数组来创建对象。当您使用 JOIN 进行 MySQL 查询时,结果将是一个包含重复项的数组。但是,在对象世界中,必须将重复的帖子合并到一个 Post 对象中......

我相信您查询的解决方案是在进行连接时进行过滤:

SELECT p,t FROM MyBundle:Post p JOIN p.tags t WITH t.value IN ('foo', 'bar')

您可以将 WITH DQL 子句理解为它在 ON MySQL 子句中添加了一个条件。即上面的查询类似于下面的MySQL查询:

SELECT p.*, t.* FROM posts AS p JOIN posts_tags AS pt ON pt.post_id = p.id JOIN tags AS t ON pt.tag_id = t.id AND t.value IN ("foo", "bar")

注意没有更多的 WHERE 子句。条件在 JOIN 条件子句中移动...

希望这可以帮助 ;-)

于 2012-12-01T17:25:23.960 回答