2

ユーザー、エリア、連絡先の 3 つのテーブルがあります。連絡先は、ユーザーまたはエリアに属することができます。ユーザーは多くのエリアに所属できます。

ユーザーに属するすべての連絡先 (DB で具体的に定義されている) と、ユーザーと同じエリアに属するすべての連絡先を取得したいと考えています。

データベース マッピングと、必要なものを取得するために DQL で記述する必要があるクエリについて、新たな視点を得ることができますか。データベースのマッピングに何か問題がありますか?

私は間違いなく SQL 派で、単純な SQL で必要なものを簡単に取得できます。プレーン SQL では、ここで私がやりたいことは次のとおりです。

 select c.* from contact c LEFT JOIN user_area ua ON c.area_id=ua.area_id where (ua.user_id=XXX OR c.user_id=XXX);

ユーザー

/**
 * @ORM\ManyToMany(targetEntity="area", inversedBy="areas")
 * @ORM\JoinTable(name="user_area",
 *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="area_id", referencedColumnName="id")}
 *      )
 */
private $areas;

/**
 * @ORM\OneToMany(targetEntity="Contact", mappedBy="user")
 */
private $contacts;

コンタクト

/**
 * @ORM\ManyToOne(targetEntity="Area")
 * @ORM\JoinColumn(name="area_id", referencedColumnName="id")
 */
private $area;

/**
 * @ORM\ManyToOne(targetEntity="User", inversedBy="Contacts")
 * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
 */
private $user;

範囲

/**
 * @ORM\ManyToMany(targetEntity="User", mappedBy="users")
 */
private $users;

/**
 * @ORM\OneToMany(targetEntity="Contact", mappedBy="area")
 */
private $contacts;

私が直面している主な問題は、DQL が実際にオブジェクトをクエリすることを望んでいるということです。SQL では、ユーザー/エリアの関係テーブルをクエリして、必要なものを取得する方が簡単です。連絡先からエリア、連絡先からユーザー、エリアからユーザーを取得するクエリを作成しようとしましたが、「ユーザー」はエリア オブジェクトで定義されたインデックスではないというエラー メッセージが表示されます。繰り返しますが、私は Doctrine の初心者なので、何か間違ったことをしている可能性があります。

これは、Symfony の User オブジェクトからクエリを試みた結果です。

    $qb = $em->createQueryBuilder()
        ->addSelect('c')
        ->from('MyBundle:Contact', 'c')
        ->leftJoin('c.area', 'ca')
        ->leftJoin('c.user', 'cu')
        ->leftJoin('ca.users', 'cau')
        ->add('where', 'c.user = ?1 OR cau.id = ?1')
        ->add('orderBy', 'c.name')
        ->setParameter(1, $this->getId());
4

2 に答える 2

1

以前の回答を提供したことで、誰かが私を平手打ちするべきでした。それは仕事を成し遂げましたが、私は完全に正しかったです.それは最適化されていませんでした. その方法を使用したクエリは、データベースとのやり取りに 3 秒かかっていました (3 秒!)。明らかに、私の世界では、これを達成するための要件としてパフォーマンスを奪う多くのことが起こっていましたが、状況は変わりました. このクエリを 2 つの小さな (Doctrine で生成された) クエリに分割することができました。それぞれに 0.2 または 0.3 秒かかりました。

    $areas = $user->getAreas();

    $qb = $this->getEntityManager()->createQueryBuilder();
    $qb->select('c')
        ->from('MyBundle:Contact', 'c')
        ->where($qb->expr()->in('c.area', '?1'))
        ->orWhere('c.user = ?2')
        ->setParameter(1, $areas->toArray())
        ->setParameter(2, $user);
    $query = $qb->getQuery();
    $result = $query->getResult();
    return $result;

私が呼び出さなければならないという事実$user->getAreas()は、データベース クエリを追加します (Doctrine がまだその情報を持っていない場合) が、このコードは、クエリ ビルダー式を使用すると、はるかにうまく機能します (0.3 秒対 3 秒は、元のクエリ時間の 10% です! )。

当時私が見逃していた主な概念は、Query Builder がオブジェクト (エンティティ) と、エンティティで定義したプロパティを操作したいということだったと思います。強力な SQL のバックグラウンドを持ち、Doctrine に生成させたい特定の SQL クエリを知っていたので、問題に適切にアプローチしていませんでした。

8 か月前の質問に対するこの更新が誰かの役に立てば幸いです。

于 2014-01-24T04:10:40.040 に答える
0

したがって、DQL ではオブジェクトのオブジェクトをフェッチできないことがわかります。すべての「エリア」(「連絡先」のオブジェクト) をフェッチしてから、そのエリアの「ユーザー」をすべてフェッチする必要がありました。

DQL では、複数の「from()」ヘルパー メソッドを指定できます。これは、仕事を完了するために必要なものでした。

$qb = $em->createQueryBuilder()
    ->addSelect('c')
    ->from('MyBundle:Contact', 'c')
    ->from('MyBundle:User', 'u')
    ->leftJoin('c.area', 'ca')
    ->leftJoin('c.user', 'cu')
    ->leftJoin('u.areas', 'ua')
    ->add('where', 'c.user = ?1 OR (ua.id=ca.id AND u.id = ?1')
    ->add('orderBy', 'c.name')
    ->setParameter(1, $this->getId());

Doctrine から生成された結果の SQL は、特に最適化されているようには見えませんが、仕事は完了しています。次のクエリをより適切に最適化するために Doctrine を使用することについて何か考えがある場合は、ぜひ意見をお聞かせください。

m0_.id AS id0、m0_.name AS name1、m0_.email AS email2、m0_.media_area_id AS media_area_id3、m0_.user_id AS user_id4 FROM contact m0_ LEFT JOIN user u1_ ON m0_.user_id = u1_.id LEFT JOIN area m2_ ON m0_.area_id = m2_.id、ユーザー u3_ LEFT JOIN user_area u5_ ON u3_.id = u5_.user_id LEFT JOIN エリア m4_ ON m4_.id = u5_.area_id WHERE u1_.id = ? OR (m4_.id = m2_.id AND u3_.id = ? );

于 2013-05-04T18:51:54.213 に答える