Doctrine Query Builder вложил условия orX и andX с объединением - PullRequest
0 голосов
/ 12 июня 2018

У меня есть две сущности User и CalendarEvent.Мои пользователи привязаны к фабрике, и CalendarEvent можно использовать, чтобы узнать, «одолжен» ли пользователь другой фабрике, к которой он принадлежит ...

Мои две сущности таковы:

Пользователь:

class User extends BaseUser
{

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @var string
     * @ORM\Column(name="firstname", type="string", length=255, nullable=true)
     */
    private $firstname;

    /**
     * @var string
     * @ORM\Column(name="lastname", type="string", length=255, nullable=true)
     */
    private $lastname;

    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\CalendarEvent", mappedBy="user")
     */
    private $events;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Factory", inversedBy="users")
     * @ORM\JoinColumn(name="factory_id", referencedColumnName="id")
     */
    private $factory;

}

CalendarEvent:

class CalendarEvent
{

    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id; 

    /**
     * @var \DateTime
     * @ORM\Column(type="datetime", name="event_start")
     */
    private $startDate;

    /**
     * @var \DateTime
     * @ORM\Column(type="datetime", name="event_end")
     */
    private $endDate;

    /**
     * @var bool
     * @ORM\Column(name="isLoan", type="boolean")
     */
    private $isLoan = TRUE;

    /**
     * @ORM\ManyToOne(targetEntity="Factory")
     * @ORM\JoinColumn(name="factory_id", referencedColumnName="id", nullable = true)
     */
    private $factory;

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

Я пытаюсь создать функцию репозитория в UserRepository, которая дает мне людей, которые на самом делеЭто фабрика, когда я запускаю запрос с фабрикой в ​​аргументе ввода ...

Чтобы достичь этого, я пытаюсь указать условие.Это условие должно выглядеть следующим образом:

select * from user where (
    (user.factory == $idfactory AND not loaned_to_other_factory) OR 
    (user.factory != $idfactory AND loaned_to_my_factory)
)

Чтобы узнать, был ли пользователь отдан в аренду моей фабрике, необходимо проверить следующее условие:

Does a record exist in CalendarEvent where startDate < NOW and endDate > NOW and loaned == true and factory == $factory

Я пытаюсь использовать пользователяи / или условия с моим репозиторием, но я так долго зависал с этим запросом, что даже не привык работать с репозиторием, так как метод findBy в большинстве случаев работает нормально ...

Я пробовал это, но у меня есть ошибка Expression of type 'Doctrine\ORM\QueryBuilder' not allowed in this context. для этой переменной $notLoanedToOther:

public function findByFactory($idFactory)
{
    $qb = $this->_em->createQueryBuilder();
    $qb->select('u')
    ->from($this->_entityName, 'u')
    ->leftJoin('u.events', 'e');

    $sub = $this->createQueryBuilder("e");
    $sub->select("e");
    $sub->from("CalendarEvent","e");
    $sub->where('e.user = u.id');
    $sub->andWhere('e.startDate < :now');
    $sub->andWhere('e.endDate > :now');

    $notLoanedToOther = $qb->where($qb->expr()->not($qb->expr()->exists($sub->getDQL())));

    $sub = $this->createQueryBuilder("e");
    $sub->select("e");
    $sub->from("CalendarEvent","e");
    $sub->where('e.user = u.id');
    $sub->where('e.factory = :idf');
    $sub->andWhere('e.startDate < :now');
    $sub->andWhere('e.endDate > :now');

    $loanedToMyFactory = $qb->where($qb->expr()->exists($sub->getDQL()));

    $condition1 = $qb->expr()->andX(
        $qb->expr()->eq('u.factory', ':idf'),
        $notLoanedToOther
    );

    $condition2 = $qb->expr()->andX(
        $qb->expr()->neq('u.factory', ':idf'),
        $loanedToMyFactory
    );

    $qb ->where($qb->expr()->orX($condition1, $condition2));

    $qb ->setParameter('idf', $idFactory);

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

Я действительно надеюсь, что имел смысл, и кто-то может дать мне советы для достижения этой цели.Заранее спасибо

Ответы [ 2 ]

0 голосов
/ 22 июня 2018

Как насчет использования простого DQL-запроса с объединениями вместо сложных, не входящих в предложения, в соответствии с указанными вами критериями в SQL

select * from user where ((user.factory == $ idfactory ANDnot loaned_to_other_factory) ИЛИ (user.factory! = $ idfactory AND loaned_to_my_factory))

Вы можете записать его эквивалент в DQL как

SELECT u
FROM User u
LEFT JOIN u.events nl WITH e.startDate < :now AND e.endDate > :now
LEFT JOIN u.events l WITH e.startDate < :now AND e.endDate > :now AND e.factory = :idf
WHERE (
    u.factory = :idf AND nl.id IS NULL
) OR (
    u.factory != :idf AND l.id IS NOT NULL
)

Присоединиться к событию дважды с пользователем с дополнительнымипункты, один для заимствованных и другой для не загруженных и затем применимых ваших условий, я добавил фильтры IS NULL и IS NOT NULL, чтобы удовлетворить ваши условия существования и отсутствия

0 голосов
/ 21 июня 2018

Полагаю, вы могли бы перевести свой запрос о существовании в не

$notLoanedToOther = $this->createQueryBuilder("e")
                         ->select("e.user")
                         ->from("CalendarEvent","e")
                         ->andWhere('e.startDate < :now')
                         ->andWhere('e.endDate > :now')
                         ->getDQL();

$loanedToMyFactory = $this->createQueryBuilder("e")
                          ->select("e.user")
                          ->from("CalendarEvent","e")
                          ->where('e.factory = :idf')
                          ->andWhere('e.startDate < :now')
                          ->andWhere('e.endDate > :now')
                          ->getDQL();

$qb = $this->_em->createQueryBuilder();
 $qb->select('u')
    ->from($this->_entityName, 'u');
    ->where(
        $qb->expr()->not(
            $qb->expr()->in(
            'u.id',
            $notLoanedToOther
            )
        )
    )
    ->andWhere(
        $qb->expr()->in(
        'u.id',
        $loanedToMyFactory
        )   
    )
    ->where(
        $qb->expr()->orX(
                $qb->expr()->andX(
                    $qb->expr()->eq('u.factory', ':idf'),
                    $qb->expr()->not(
                        $qb->expr()->in(
                        'u.id',
                        $notLoanedToOther
                        )
                    )
                ), 
                $qb->expr()->andX(
                    $qb->expr()->neq('u.factory', ':idf'),
                    $qb->expr()->in(
                    'u.id',
                    $loanedToMyFactory
                    )
                )
            )
        )
    ->setParameter('idf', $idFactory)
    ->setParameter('now', $someDate)
    ;

Выполнение подзапроса WHERE .. IN в Doctrine 2

...