3

(Symfony プロジェクトで) Doctrine クエリを構築するのに多くのトラブルを経験しました。完成したばかりで動作しますが、あなたのアドバイスが欲しいです。 .

簡単にするために、WorkshopNews、およびCommentの 3 つの SQL テーブルを用意しました。最後の 2 つは、Workshop との ManyToOne 関係にあります。

私の目標は、Workshop エンティティと関連する News および Comment エンティティを 1 つのページに表示することです。少し複雑にするために、最後の 5 つの News エンティティと Comment エンティティだけを表示する必要があります。もちろん、これは 1 つのクエリで実行する必要があります (トラブルシューティングとして、今まで遅延読み込みを使用していました)。

私はこのネイティブクエリを作成することができました:

SELECT *
FROM Workshop w
LEFT JOIN (
    SELECT * FROM News ORDER BY id DESC LIMIT 0, 5
) n ON w.id = n.workshop_id
LEFT JOIN (
    SELECT * FROM Comment ORDER BY id DESC LIMIT 0, 5
) c ON w.id = c.workshop_id
WHERE w.id = 1 -- Random ID as an exemple

この後、DQL に変換したいと思ったのですが、この言語は FROM セクションと JOIN セクション内のネストされたクエリをサポートしていません。

私が持っていた最後の選択肢は、ネイティブ クエリを使用することでした...しばらくすると、ワークショップ リポジトリ内で次の結果を取得できるようになりました。

<?php

public function getWorkshopWithAllContent()
{
    $rsm = new ResultSetMappingBuilder($this->_em);

    $rsm->addRootEntityFromClassMetadata('FON\WorkshopBundle\Entity\Workshop', 'w', array(
        'id' => 'wId'
    ));

    $rsm->addJoinedEntityFromClassMetadata('FON\WorkshopBundle\Entity\News', 'n', 'w', 'news', array(
        'id' => 'nId',
        'title' => 'nTitle',
        'content' => 'nContent',
        'pubDatetime' => 'nPubDatetime',
        'validated' => 'nValidated',
        'workshop_id' => 'nWorkshop_id'
    ));

    $rsm->addJoinedEntityFromClassMetadata('FON\WorkshopBundle\Entity\Comment', 'c', 'w', 'comments', array(
        'id' => 'cId',
        'title' => 'cTitle',
        'content' => 'cContent',
        'pubDatetime' => 'cPubDatetime',
        'validated' => 'cValidated',
        'workshop_id' => 'cWorkshop_id'
    ));

    $query = $this->_em->createNativeQuery(
        'SELECT '.
            'w.id wId, w.town, w.description, w.zipcode, w.address, '.
            'n.id nId, n.title nTitle, n.content nContent, n.pubDatetime nPubDatetime, n.validated nValidated, n.workshop_id nWorkshop_id, '.
            'c.id cId, c.title cTitle, c.content cContent, c.pubDatetime cPubDatetime, c.validated cValidated, c.workshop_id cWorkshop_id '.
        'FROM Workshop w '.
        'LEFT JOIN ( '.
        '    SELECT * FROM News ORDER BY id DESC LIMIT 0, 5 '.
        ') n ON w.id = n.workshop_id '.
        'LEFT JOIN ( '.
        '    SELECT * FROM Comment ORDER BY id DESC LIMIT 0, 5 '.
        ') c ON w.id = c.workshop_id '.
        'WHERE w.id = 1 ',
        $rsm
    );

    return $query->getOneOrNullResult();
}

では、なぜほとんどすべての列を再定義するのでしょうか? 私がそれをしなければ、このように:

<?php

public function getWorkshopWithAllContent()
{
    $rsm = new ResultSetMappingBuilder($this->_em);

    $rsm->addRootEntityFromClassMetadata('FON\WorkshopBundle\Entity\Workshop', 'w');

    $rsm->addJoinedEntityFromClassMetadata('FON\WorkshopBundle\Entity\News', 'n', 'w', 'news');

    $rsm->addJoinedEntityFromClassMetadata('FON\WorkshopBundle\Entity\Comment', 'c', 'w', 'comments');

    $query = $this->_em->createNativeQuery(
        'SELECT * '.
        'FROM Workshop w '.
        'LEFT JOIN ( '.
        '    SELECT * FROM News ORDER BY id DESC LIMIT 0, 5 '.
        ') n ON w.id = n.workshop_id '.
        'LEFT JOIN ( '.
        '    SELECT * FROM Comment ORDER BY id DESC LIMIT 0, 5 '.
        ') c ON w.id = c.workshop_id '.
        'WHERE w.id = 1 ',
        $rsm
    );

    return $query->getOneOrNullResult();
}

このエラーが発生します:

The column 'id' conflicts with another column in the mapper.

以上です!私の質問は今です:より良い解決策はありますか?私の話はとても長く、Doctrine が解決策を考えていなかったことに驚いています。

これを解決する恒久的な方法は、テーブルのすべての列の名前を変更することですが、これを行う前にもっと簡単な解決策があるかどうか知りたいです。

ありがとうございました。

4

1 に答える 1

0

Doctrine の結合インターフェースは自然ですが、内部でかなりの処理を行うため、単純に sql を拡張しようとするとつまずくことがあります。エンティティ構造が表示されていないため、ワークショップは次のようになっていると思います。

YAML (私の好み):

Workshop:
  type: entity
  << other fields >>
  manyToOne:
    news:
      targetEntity: News
    comment:
      targetEntity: Comment

または同等の注釈(ほとんどのスタックオーバーフロー記事は注釈にあるように見えるため、含める必要があります):

class Workshop {
//... << other fields >>
/**
 * @ManyToOne(targetEntity="News")
 * @JoinColumn(name="news_id", referencedColumnName="id")
 */
private $comment;
/**
 * @ManyToOne(targetEntity="Comment")
 * @JoinColumn(name="comment_id", referencedColumnName="id")
 */
private $comment;
//...
}

試す:

public function getWorkshopWithAllContent($id){

    $qb= $this->_em->createQueryBuilder('w');
    $qb->leftJoin('w.news', 'n')
       ->leftJoin('w.comment', 'c')
       ->andWhere($qb->expr()->eq('w.id',$id));

    return $qb->getQuery()->getResult();

}

Dotcrine は、SQL で明示的に指定した ID の一致を処理します。クエリを改良するその他の方法については、http://docs.doctrine-project.org/en/2.0.x/reference/query-builder.htmlを確認してください。

于 2012-11-23T05:39:46.563 に答える