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)を使用すると、DBは投稿テーブル全体をスキャンしてから、セットをタグ付けされたものに減らすと思います

(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」、...) にあるタグが少なくとも 1 つあるすべての投稿を選択し、他のすべての投稿を無視することをお勧めします。

(3) から始めましょう:

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

MySQL では、これはおおよそ、「値が foo または bar のいずれかであるタグを持つすべての投稿を選択する」ことを意味します。

ただし、DQL では、これは「すべての投稿を選択し、値が foo または bar のいずれかであるタグのみを添付する」ことを意味します。つまり、クエリはすべての投稿のセットを返しますが、タグはフィルターされています。この動作の違いは、doctrine がデータベース層によって返された配列でオブジェクトを作成する必要があるという事実によるものです。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 に答える