[英]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:
- 2000-01-01 - 2000-01-02
- 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.