Конструктор запросов Doctrine с использованием внутреннего соединения с условиями
Я хотел бы построить следующий SQL, используя конструктор запросов Doctrine:
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. Спасибо заранее!
Примечание. Я знаю, что мы также можем написать родной mysql или dql с помощью Doctrine, но я бы предпочел построитель запросов.
EDIT: Ниже приведен весь код
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();
}
}
Ответы
Ответ 1
Я собираюсь ответить на свой вопрос.
- innerJoin должен использовать ключевое слово "WITH" вместо "ON" (документация Doctrine [13.2.6. Методы помощника] неточна, [13.2.5. Класс Expr] правильный)
- Не нужно связывать внешние ключи в состоянии соединения, поскольку они уже указаны в сопоставлении сущностей.
Поэтому для меня работает следующее
$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');
Ответ 2
Вы можете явно иметь такое соединение:
$qb->innerJoin('c.phones', 'p', Join::ON, 'c.id = p.customerId');
Но вам нужно использовать пространство имен класса Join from doctrine:
use Doctrine\ORM\Query\Expr\Join;
Или, если вы так предпочитаете:
$qb->innerJoin('c.phones', 'p', Doctrine\ORM\Query\Expr\Join::ON, 'c.id = p.customerId');
В противном случае Присоединить класс не будет обнаружен, а ваш script выйдет из строя...
Здесь конструктор метода 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
ИЗМЕНИТЬ
Думаю, что это должно быть:
$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, возможно, проблема.