Doctrine QueryBuilder нужно изменить условие ON для leftJoin

0

У меня есть собственный sql-запрос с левым соединением, когда есть или с условием, как представить его в построителе запросов?

 $query = "  SELECT  te.id
            FROM    task_executions AS te
            INNER JOIN tasks AS t ON t.id = te.task_id
            LEFT JOIN cost_objects AS co ON co.id = t.cost_object_id
            LEFT JOIN cost_object_managers AS com ON com.cost_object_id = co.id OR com.cost_object_id = co.parent_id

и мне нужно представить его в построителе запросов. Но в объекте User меня есть отношение ManyToMany, без отдельной таблицы, и когда я пытаюсь выполнить условие join join WITH это не то, что мне нужно. Мне нужно изменить отношение для ON

LEFT JOIN cost_object_managers AS com ON com.cost_object_id = co.id OR com.cost_object_id = co.parent_id

Пользовательский объект

class User
{
...
/**
 * @ORM\ManyToMany(targetEntity="CostObject", mappedBy="users")
 */
private $costObjects;
}

Объект CostObject

class CostObject
{
    /**
 * @var CostObject
 *
 * @ORM\ManyToOne(targetEntity="CostObject", inversedBy="children")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE")
 * })
 */
private $parent;

    /**
 * @var ArrayCollection
 *
 * @ORM\ManyToMany(targetEntity="User", inversedBy="costObjects")
 * @ORM\JoinTable(name="cost_object_managers",
 *      joinColumns={@ORM\JoinColumn(name="cost_object_id", referencedColumnName="id", onDelete="CASCADE")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE")}
 * )
 */
private $users;

и мой построитель запросов без условия

        $qb->select('te')
        ->from('AppBundle:TaskExecution', 'te')
        ->innerJoin('te.task', 't')

        ->leftJoin('t.costObject', 'co')
        ->leftJoin('co.users', 'com')

это $query->getSQL()

SELECT some_name FROM task_executions t0_ INNER JOIN tasks t1_ ON t0_.task_id = t1_.id LEFT JOIN cost_objects c2_ ON t1_.cost_object_id = c2_.id LEFT JOIN cost_object_managers c4_ ON c2_.id = c4_.cost_object_id LEFT JOIN users u3_ ON u3_.id = c4_.user_id ORDER BY t0_.execution_start DESC

В этом примере я вижу условие ON отношения LEFT JOIN users u3_ ON u3_.id = c4_.user_id. И нужно изменить его, как в родном sql

Теперь у меня есть

        $qb->select('te')
        ->from('AppBundle:TaskExecution', 'te')
        ->innerJoin('te.task', 't')
        ->leftJoin('t.costObject', 'co')
        ->leftJoin(
            'co.users',
            'com',
            Join::ON,
            $qb->expr()->orX(
                'co = com.costObjects',
                'co.parent = com.costObjects'
            )
        )

но получил ошибку

[Syntax Error] line 0, col 112: Error: Expected end of string, got 'ON'

если я использовал условие WITH, в моем sql-представлении у меня все еще есть отношение по id, мне это не нужно

            ->leftJoin(
            'co.users',
            'com',
            Join::WITH,
            $qb->expr()->orX(
                'co MEMBER OF com.costObjects',
                'co.parent MEMBER OF com.costObjects'
            )
        )

LEFT JOIN users u3_ ON u3_.id = c4_.user_id AND (EXISTS (SELECT 1 FROM cost_object_managers c5_ INNER JOIN cost_objects c6_ ON c5_.cost_object_id = c6_.id WHERE c5_.user_id = u3_.id AND c6_.id IN (c2_.id)) OR EXISTS (SELECT 1 FROM cost_object_managers c5_ INNER JOIN cost_objects c6_ ON c5_.cost_object_id = c6_.id WHERE c5_.user_id = u3_.id AND c6_.id IN (c2_.parent_id)))

Я имею в виду users u3_ ON u3_.id = c4_.user_id AND но в исходном запросе мы имеем только LEFT JOIN cost_object_managers AS com ON com.cost_object_id = co.id OR com.cost_object_id = co.parent_id

Как он воспроизводится в Query Builder с типом состояния ON?

Теги:
sql-server
doctrine2

1 ответ

0

Если у вас есть запрос и он работает для вас, вам не нужно выполнять всю работу, чтобы преобразовать его в DQL или программный синтаксис QueryBuilder. Вы можете просто использовать Doctrine Native Query, а затем - при необходимости - сопоставить результат с вашим объектом. Просто создайте пользовательский репозиторий и в нем новый метод, который примерно выглядит следующим образом:

public function findTaskExecutionBy...()
{
    $query = $this->entityManager->createNativeQuery('SELECT te.id FROM ...');

    return $query->getSingleScalarResult(); // If it just one id you expect
}

Вы также можете использовать $query->getResult() если вы ожидаете возвращения нескольких идентификаторов. Или используйте ResultSetMapping, если вы хотите весь объект Task:

$rsm = new ResultSetMappingBuilder($this->entityManager);
$rsm->addRootEntityFromClassMetadata('App\Entity\Task', 'te');

$query = $this->entityManager->createNativeQuery(
    'SELECT te.* FROM ...',

Вы также можете проверить документацию Doctrine для более подробного объяснения и еще несколько примеров: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/native-sql.html $ rsm);

  • 0
    Большой хороший совет Если у вас есть запрос, и он работает для вас, вам не нужно делать всю работу, чтобы преобразовать его в DQL
  • 1
    В моем случае мне нужен запрос построителя запросов

Ещё вопросы

Сообщество Overcoder
Наверх
Меню