Where IN 查询 Doctrine ManyToMany 标签关系
Where IN query on Doctrine ManyToMany tags relation
一些背景知识:
- 我有 Office 实体。
- 办公室可能有文章。
- 文章有标签。
- 办公室可以与其他办公室(以及文章)共享标签。
现在我正在尝试构建一个查询:"Fetch all articles that either belong to my office or have tags that have been shared with my office"。
我已经在 MySQL 中尝试过,下面的查询按预期工作:
SELECT
*
FROM
`articles` `a`
WHERE
(
`office_id` = 2
OR
`a`.`id` IN (
SELECT
`at`.`article_id`
FROM
`article_tags` `at`
WHERE
`at`.`article_id` = `a`.`id`
AND
`at`.`tag_id` IN
(
SELECT
`st`.`tag_id`
FROM
`shared_tags` `st`
WHERE
`st`.`shared_with_id` = 2
AND
`st`.`article` = 1
)
)
)
AND
`status` = 1
我的实体如下:
文章
/**
* @ORM\ManyToMany(targetEntity="Tag", inversedBy="articles")
* @ORM\JoinTable(name="article_tags")
* @var ArrayCollection|Tag[]
*/
protected $tags;
标签
/**
* @ORM\ManyToMany(targetEntity="Article", mappedBy="tags")
* @var ArrayCollection|Article[]
*/
protected $articles;
共享标签
class SharedTag extends Entity
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
* @var int
*/
protected $id;
/**
* @ORM\ManyToOne(targetEntity="Office", inversedBy="sharedTags")
* @ORM\JoinColumn(name="shared_with_id", referencedColumnName="id")
* @var Office
*/
protected $sharedWith;
/**
* @ORM\ManyToOne(targetEntity="Office", inversedBy="sharedTags")
* @ORM\JoinColumn(name="shared_by_id", referencedColumnName="id")
* @var Office
*/
protected $sharedBy;
/**
* @ORM\ManyToOne(targetEntity="Tag", inversedBy="sharedTags")
* @var Tag
*/
protected $tag;
/**
* @ORM\Column(type="boolean", options={"default" = 0})
* @var bool
*/
protected $template = 0;
/**
* @ORM\Column(type="boolean", options={"default" = 0})
* @var bool
*/
protected $article = 0;
/**
* @ORM\Embedded(class = "\ValueObjects\CreatedAt", columnPrefix=false)
* @var CreatedAt
*/
protected $createdAt;
}
那么,如何在 DQL 中或使用 QueryBuilder 进行查询?我尝试了几种方法,但我似乎无法在 WHERE IN() 查询中使用关系 articles.tags
中的 tag_id
。
提前致谢!
编辑:
经过反复试验并感谢 Jean 的回答,我能够像这样查询它:
SELECT
a
FROM
Article a
LEFT JOIN a.tags t
LEFT JOIN a.office o
LEFT JOIN o.sharedTags st
WHERE
(
a.office = :office
OR
(
t = st.tag
AND
st.sharedWith = :office
AND
st.article = 1
)
)
AND
a.status.status = :status
AND
a.template IS NULL
GROUP BY a.id
您应该使用联接而不是子查询。这样你就可以获得更好的性能和更简单的 DQL 代码:
SELECT DISTINCT `a`
FROM `articles` `a`
LEFT JOIN `a.tags` `t`
LEFT JOIN `t.shared_with_id` `o`
WHERE (`a`.`office_id` = 2 OR `o`.`id` = 2)
AND `status` = 1
一些背景知识:
- 我有 Office 实体。
- 办公室可能有文章。
- 文章有标签。
- 办公室可以与其他办公室(以及文章)共享标签。
现在我正在尝试构建一个查询:"Fetch all articles that either belong to my office or have tags that have been shared with my office"。
我已经在 MySQL 中尝试过,下面的查询按预期工作:
SELECT
*
FROM
`articles` `a`
WHERE
(
`office_id` = 2
OR
`a`.`id` IN (
SELECT
`at`.`article_id`
FROM
`article_tags` `at`
WHERE
`at`.`article_id` = `a`.`id`
AND
`at`.`tag_id` IN
(
SELECT
`st`.`tag_id`
FROM
`shared_tags` `st`
WHERE
`st`.`shared_with_id` = 2
AND
`st`.`article` = 1
)
)
)
AND
`status` = 1
我的实体如下:
文章
/**
* @ORM\ManyToMany(targetEntity="Tag", inversedBy="articles")
* @ORM\JoinTable(name="article_tags")
* @var ArrayCollection|Tag[]
*/
protected $tags;
标签
/**
* @ORM\ManyToMany(targetEntity="Article", mappedBy="tags")
* @var ArrayCollection|Article[]
*/
protected $articles;
共享标签
class SharedTag extends Entity
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
* @var int
*/
protected $id;
/**
* @ORM\ManyToOne(targetEntity="Office", inversedBy="sharedTags")
* @ORM\JoinColumn(name="shared_with_id", referencedColumnName="id")
* @var Office
*/
protected $sharedWith;
/**
* @ORM\ManyToOne(targetEntity="Office", inversedBy="sharedTags")
* @ORM\JoinColumn(name="shared_by_id", referencedColumnName="id")
* @var Office
*/
protected $sharedBy;
/**
* @ORM\ManyToOne(targetEntity="Tag", inversedBy="sharedTags")
* @var Tag
*/
protected $tag;
/**
* @ORM\Column(type="boolean", options={"default" = 0})
* @var bool
*/
protected $template = 0;
/**
* @ORM\Column(type="boolean", options={"default" = 0})
* @var bool
*/
protected $article = 0;
/**
* @ORM\Embedded(class = "\ValueObjects\CreatedAt", columnPrefix=false)
* @var CreatedAt
*/
protected $createdAt;
}
那么,如何在 DQL 中或使用 QueryBuilder 进行查询?我尝试了几种方法,但我似乎无法在 WHERE IN() 查询中使用关系 articles.tags
中的 tag_id
。
提前致谢!
编辑:
经过反复试验并感谢 Jean 的回答,我能够像这样查询它:
SELECT
a
FROM
Article a
LEFT JOIN a.tags t
LEFT JOIN a.office o
LEFT JOIN o.sharedTags st
WHERE
(
a.office = :office
OR
(
t = st.tag
AND
st.sharedWith = :office
AND
st.article = 1
)
)
AND
a.status.status = :status
AND
a.template IS NULL
GROUP BY a.id
您应该使用联接而不是子查询。这样你就可以获得更好的性能和更简单的 DQL 代码:
SELECT DISTINCT `a`
FROM `articles` `a`
LEFT JOIN `a.tags` `t`
LEFT JOIN `t.shared_with_id` `o`
WHERE (`a`.`office_id` = 2 OR `o`.`id` = 2)
AND `status` = 1