web-dev-qa-db-ja.com

Doctrine条件付き内部結合を使用したクエリビルダー

Doctrineのクエリビルダーを使用して次のSQLを構築したいと思います:

select c.*
from customer c
join phone p
on p.customer_id = c.id
and p.phone = :phone
where c.username = :username

最初に試した

$qb->select('c')
    ->innerJoin('c.phones', 'p', Join::ON, $qb->expr()->andx(
        $qb->expr()->eq('p.customerId', 'c.id'),
        $qb->expr()->eq('p.phone', ':phone')
    ))
    ->where('c.username = :username');

しかし、私は次のエラーを受け取っています

Error: expected end of string, got 'ON'

それから私は試した

$qb->select('c')
    ->innerJoin('c.phones', 'p')
    ->where('c.username = :username')
    ->andWhere('p.phone = :phone');

動作しているようです。しかし、誰もが最初の試みの何が問題なのか知っていますか? SQLがどのように構造化されているかに似ているため、最初の1つを機能させたいと思います。前もって感謝します!

注:Doctrineを使用してネイティブmysqlまたはdqlを作成することもできますが、クエリビルダーを使用することをお勧めします。

編集:以下はコード全体です

namespace Cyan\CustomerBundle\Repository;

use Cyan\CustomerBundle\Entity\Customer;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr\Join;

class CustomerRepository extends EntityRepository
{
    public function findCustomerByPhone($username, $phone)
    {
        $qb = $this->createQueryBuilder('c');

        $qb->select('c')
            ->innerJoin('c.phones', 'p', Join::ON, $qb->expr()->andx(
                $qb->expr()->eq('p.customerId', 'c.id'),
                $qb->expr()->eq('p.phone', ':phone')
            ))
            ->where('c.username = :username');

//        $qb->select('c')
//            ->innerJoin('c.phones', 'p')
//            ->where('c.username = :username')
//            ->andWhere('p.phone = :phone');

        $qb->setParameters(array(
            'username' => $username,
            'phone' => $phone->getPhone(),
        ));

        $query = $qb->getQuery();
        return $query->getResult();
    }
}
35
Mr. 14

私は自分の質問に答えます。

  1. innerJoinは「ON」の代わりにキーワード「WITH」を使用する必要があります(Doctrineのドキュメント[13.2.6。Helperメソッド]は不正確です; [13.2.5。Exprクラス]は正しいです)
  2. エンティティマッピングで既に指定されているため、結合条件で外部キーをリンクする必要はありません。

したがって、私にとって次の作品

$qb->select('c')
    ->innerJoin('c.phones', 'p', 'WITH', 'p.phone = :phone')
    ->where('c.username = :username');

または

$qb->select('c')
    ->innerJoin('c.phones', 'p', Join::WITH, $qb->expr()->eq('p.phone', ':phone'))
    ->where('c.username = :username');
82
Mr. 14

次のように明示的に結合できます。

$qb->innerJoin('c.phones', 'p', Join::ON, 'c.id = p.customerId');

ただし、DoctrineのJoinクラスの名前空間を使用する必要があります。

use Doctrine\ORM\Query\Expr\Join;

または、そのようにしたい場合:

$qb->innerJoin('c.phones', 'p', Doctrine\ORM\Query\Expr\Join::ON, 'c.id = p.customerId');

そうでなければ、 Join class は検出されず、スクリプトはクラッシュします...

ここで、innerJoinメソッドのコンストラクター:

public function innerJoin($join, $alias, $conditionType = null, $condition = null);

他の可能性(「ON」に参加するだけでなく、「WITH」など)もここにあります: http://docs.doctrine-project.org/en/2.0.x/reference/ query-builder.html#the-expr-class

[〜#〜] edit [〜#〜]

それがあるべきだと思う:

$qb->select('c')
    ->innerJoin('c.phones', 'p', Join::ON, 'c.id = p.customerId')
    ->where('c.username = :username')
    ->andWhere('p.phone = :phone');

    $qb->setParameters(array(
        'username' => $username,
        'phone' => $phone->getPhone(),
    ));

そうでなければ、おそらくあなたはONとWITHの混合を実行していると思います。

10
Sybio