[英]Laravel/Eloquent: Constrain nested eager load so as not to include empty parents
我有一个相对简单的数据库结构,包括国家、地区和仓库。 每个仓库都分配给一个操作员和一个区域:
运营商
+----+------------+
| ID | name |
+----+------------+
| 1 | Operator 1 |
| 2 | Operator 2 |
+----+------------+
国家
+----+----------------+------+
| ID | country_id | code |
+----+----------------+------+
| 1 | United Kingdom | gb |
| 2 | France | fr |
+----+----------------+------+
地区
+----+-----------------+-------+
| ID | country_id (FK) | name |
+----+-----------------+-------+
| 1 | 1 | North |
| 2 | 1 | South |
| 3 | 1 | East |
| 4 | 1 | West |
| 5 | 2 | North |
| 6 | 2 | South |
| 7 | 2 | East |
| 8 | 2 | West |
+----+-----------------+-------+
仓库
+----+----------------+------------------+-----------+
| ID | region_id (FK) | operator_id (FK) | name |
+----+----------------+------------------+-----------+
| 1 | 1 | 1 | Newcastle |
| 2 | 8 | 2 | Nantes |
+----+----------------+------------------+-----------+
我已经在各自的模型中成功地建立了他们雄辩的关系。
我想加载按各自地区和国家分组的每个仓库,并由特定运营商过滤。
$depots = Country::with('regions.depots')->whereHas('regions.depots', function($query) use ($opID) {
$query->where('operator_id',$opID);
})->get();
这可以解决问题,但是,除了急切加载 depot 之外,它还急切加载所有区域,包括那些没有分配 depot 的区域。 当$opID = 1
时执行上述 EG 时,您会得到以下结果:
name: United Kingdom,
regions: [
{
name: North,
depots: [{
name: Newcastle
}]
}, {
name: South,
depots: []
}, {
name: East,
depots: []
}, {
name: West,
depots: []
}
]
我想要的是上面返回的,但没有没有仓库的区域。
我身边有很多打了双方的约束with
和whereHas
,但不能得到所需的数据结构。 为什么下面的代码没有预期的效果?
$depots = Country::with(['regions.depots' => function($query) use ($opID) {
$query->where('depots.operator_id',$opID);
}])->get();
如果孩子不存在,有没有办法不急切地加载父母? 还是按照我的方式执行上述查询,然后手动遍历结果?
编辑
所以几个小时后,我终于找到了一种方法来获得我想要的结果。 不过好像真的很脏。 这真的是最好的方法吗?
$depots = Country::whereHas('regions.depots', function($q) use ($opID) {
$q->where('operator_id',$opID);
})->with(['regions' => function($q) use ($opID) {
$q->with('depots')->whereHas('depots', function($q2) use ($opID) {
$q2->where('operator_id',$opID);
});
}])->get();
编辑 2
所以事实证明,第一次编辑实际上是在除depots
表之外的所有内容上查询operator_id
,这意味着一旦我在同一地区添加了另一个运营商拥有的另一个 depot,它就会在我不想要的时候出现。 下面看起来更混乱,但确实有效。 与自己交谈很有趣 ;) 希望有一天它可以帮助某人......
$depots = Country::has('regions.depots')
->with(['regions' => function($q) use ($opID) {
$q->with(['depots' => function($q2) use ($opID) {
$q2->where('operator_id',$opID);
}])->has('depots');
}])->get();
您始终可以使用延迟加载:
$depots = Country::whereHas('regions.depots', function($q) use ($opID) {
$q->where('operator_id',$opID);
})->get()->load('regions.depots');
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.