簡體   English   中英

嘗試使用 doctrine 查詢生成器的 select 左連接為 null

[英]trying to select where left join is null using doctrine query builder

我正在嘗試 select 所有在給定預訂日期未被占用的房間。
我創建了這樣的代碼:

$queryBuilder->select('rm')
            ->from('App:Room', 'rm')
            ->leftJoin('App:Reservation', 'r', 'WITH', $queryBuilder->expr()->andX(
                $queryBuilder->expr()->lt('r.start', '?1'),
                $queryBuilder->expr()->gt('r.stop', '?2'),
                $queryBuilder->expr()->neq('r.status', '?3')
                )
            )->where(
                $queryBuilder->expr()->andX(
                    $queryBuilder->expr()->isNull('r')
                )
            )->setParameters(
                array(
                    1 => $stop,
                    2 => $start,
                    3 => Reservation::STATUS_EXPIRED
                )
            ); 

我在 2 個房間有 2 個預訂,其中房間 ID 等於預訂 ID:

  1. 2000-01-01 - 2000-01-02
  2. 2000-01-01 - 2000-01-03

另外$start = '2000-01-02'$stop = '2000-01-05'並且兩個預訂的狀態都是Reservation::STATUS_NEW
我希望給定這些日期,此查詢將返回房間 1。因為房間 2 的預訂與它們發生沖突,但結果為空。
刪除where子句會導致兩個房間都被返回。 在這種情況下$queryBuilder->getQuery()->getArrayResult()返回房間和預訂號 2。正如預期的那樣,但是當我恢復where子句時,數組只是空的。

我的另一種方法是通過子查詢,但它的行為完全相同,所以請告知,我錯過了什么?

$queryBuilder = $this->getEntityManager()->createQueryBuilder();
        $all = $this->getEntityManager()->createQueryBuilder();

        $all->select('rma.id')
            ->from('App:Room', 'rma')
            ->innerJoin('App:Reservation', 'r')
            ->where(
                $all->expr()->andX(
                    $all->expr()->lt('r.start', '?1'),
                    $all->expr()->gt('r.stop', '?2'),
                    $all->expr()->neq('r.status', '?3')
                )
            );

        $queryBuilder->select('rm')
            ->from('App:Room', 'rm')
            ->where(
                $queryBuilder->expr()->neq(
                    'rm.id',
                    $queryBuilder->expr()->all(
                        $all->getDQL()
                    )
                )
            )->setParameters(
                array(
                    1 => $stop,
                    2 => $start,
                    3 => Reservation::STATUS_EXPIRED
                )
            );

您可能希望排除預訂與查詢日期范圍重疊的房間。

那是

$queryBuilder->expr()->lt('r.start', '?1'), // 1 being stop
$queryBuilder->expr()->gt('r.stop', '?2'),  // 2 being start

你已經正確了。 但是,您的 null 檢查已關閉,它應該是:

$queryBuilder->expr()->isNull('r') // <-- you had rm here

所以, r顯然是保留,應該是 null(“缺失”)。

(我總是發現使用短別名真的很難發現這些錯誤,而且實際節省的時間很少......,我也更喜歡命名參數而不是編號參數)

更新

好的,我錯過了這里錯誤的要點;o/

您的查詢匹配所有預訂的房間(不僅僅是該房間的預訂),並選擇那些“沒有”預訂的房間。 含義:如果在日期范圍內有預訂,則返回 NO 房間,如果在日期范圍內沒有預訂,則返回所有房間。

有兩種方法可以讓查詢構建器做正確的事情,這取決於您的映射定義,但我會假設Room實體有一個字段reservations保存該房間的所有預訂。

$qb->from('Room', 'rm')
   ->leftJoin('rm.reservations', 'r', 'WITH', ...)

不同之處在於,“桌子”描述符意味着預訂是各自房間的,並且只與那些房間相連。

或者是明確的:

$qb->from('Room', 'rm')
   ->leftJoin('Reservation', 'r', 'WITH', $qb->expr()->andX('r.room=rm', ...))

那應該最終解決您的問題。

上面的答案使我走上了正確的軌道,以了解我的失敗。
我的最終代碼如下所示:

$queryBuilder->select('rm')
            ->from('App:Room', 'rm')
            ->leftJoin('rm.reservations', 'r', 'WITH', $queryBuilder->expr()->andX(
                $queryBuilder->expr()->lt('r.start', '?1'),
                $queryBuilder->expr()->gt('r.stop', '?2'),
                $queryBuilder->expr()->neq('r.status', '?3')
                )
            )->where(
                $queryBuilder->expr()->andX(
                    $queryBuilder->expr()->isNull('r')
                )
            )->setParameters(
                array(
                    1 => $stop,
                    2 => $start,
                    3 => Reservation::STATUS_EXPIRED
                )
            );

這完全是關於加入rm.reservations ,而不是像我一樣加入一般的App:Reservation 如果我指向 object 的字段而不是一般的 class 的字段,則關聯在實體類中定義得很好,並且 Doctrine 將添加適當的約束。
Jakumi 給出的示例適用於 ManyToOne 關聯,在我的情況下(ManyToMany),我必須手動加入 Reservation 和 Room 之間的連接表。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM