Doctrine 查询生成器使用 join 嵌套 orX 和 andX 条件

问题描述 投票:0回答:2

我有两个实体

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;

}

日历事件:

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();
}

我真的希望我说得有道理,有人可以给我一些建议来实现这一目标。预先感谢

join doctrine repository conditional-statements query-builder
2个回答
8
投票

我想你可以将你的存在查询翻译为 not in

$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);

在原则 2 中执行 WHERE .. IN 子查询


1
投票

如何根据您在 SQL 中指定的条件,使用带有联接的简单 DQL 查询而不是复杂的 not in 子句

从用户中选择*,其中( (user.factory == $idfactory 并且不借给其他工厂) 或者 (user.factory != $idfactory AND 借用_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
过滤器来满足您的存在和不存在条件

© www.soinside.com 2019 - 2024. All rights reserved.