繁体   English   中英

Laravel/Eloquent:限制嵌套的急切加载,以免包含空的父母

[英]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: []
    }
]

我想要的是上面返回的,但没有没有仓库的区域。

我身边有很多打了双方的约束withwhereHas ,但不能得到所需的数据结构。 为什么下面的代码没有预期的效果?

$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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM