使用学说查询生成器尝试 select 左连接为空的地方
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
我希望根据这些日期,此查询将 return 我的房间 1.,因为房间 2 的预订与他们发生冲突,但结果是空的。
删除 where
子句会导致两个房间都被 returned。在这种情况下 $queryBuilder->getQuery()->getArrayResult()
return 房间和预订号 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
你已经猜对了。但是,您的空检查已关闭,它应该是:
$queryBuilder->expr()->isNull('r') // <-- you had rm here
所以,r
显然是保留,那个应该是空的("missing")。
(我总是发现使用短别名真的很难发现这些类型的错误,而且实际节省的时间太少了......,我也更喜欢命名参数而不是编号参数)
更新
好吧,我错过了这里的要点;o/
您的查询匹配所有 all 预订的房间(不仅仅是那个房间的预订),并选择那些 "have" 没有预订的房间。含义:如果该日期范围内有预订,您将无法获得任何房间,如果该日期范围内没有预订,您将获得所有房间。
有两种方法可以使查询生成器做正确的事情,这取决于您的映射定义,但我假设,Room
实体有一个字段 reservations
保存所有保留那个房间。
$qb->from('Room', 'rm')
->leftJoin('rm.reservations', 'r', 'WITH', ...)
不同之处在于,"table" 描述符 暗示 预订是针对相应房间的,并且仅与这些房间合并。
或明确:
$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
。关联在实体 classes 中定义明确,如果我指向对象的字段而不是一般 class.
,则 Doctrine 将添加适当的约束
Jakumi 给出的示例对于 ManyToOne 关联可以正常工作,在我的情况下(ManyToMany)我将不得不手动加入 Reservation 和 Room 之间的加入 table。
我正在尝试 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
我希望根据这些日期,此查询将 return 我的房间 1.,因为房间 2 的预订与他们发生冲突,但结果是空的。
删除 where
子句会导致两个房间都被 returned。在这种情况下 $queryBuilder->getQuery()->getArrayResult()
return 房间和预订号 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
你已经猜对了。但是,您的空检查已关闭,它应该是:
$queryBuilder->expr()->isNull('r') // <-- you had rm here
所以,r
显然是保留,那个应该是空的("missing")。
(我总是发现使用短别名真的很难发现这些类型的错误,而且实际节省的时间太少了......,我也更喜欢命名参数而不是编号参数)
更新
好吧,我错过了这里的要点;o/
您的查询匹配所有 all 预订的房间(不仅仅是那个房间的预订),并选择那些 "have" 没有预订的房间。含义:如果该日期范围内有预订,您将无法获得任何房间,如果该日期范围内没有预订,您将获得所有房间。
有两种方法可以使查询生成器做正确的事情,这取决于您的映射定义,但我假设,Room
实体有一个字段 reservations
保存所有保留那个房间。
$qb->from('Room', 'rm')
->leftJoin('rm.reservations', 'r', 'WITH', ...)
不同之处在于,"table" 描述符 暗示 预订是针对相应房间的,并且仅与这些房间合并。
或明确:
$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
。关联在实体 classes 中定义明确,如果我指向对象的字段而不是一般 class.
,则 Doctrine 将添加适当的约束
Jakumi 给出的示例对于 ManyToOne 关联可以正常工作,在我的情况下(ManyToMany)我将不得不手动加入 Reservation 和 Room 之间的加入 table。