Laravel 8.42:如何在hasOneThrough关联中使用latestOfMany?
在Laravel的hasOneThrough关联中实现类似latestOfMany的逻辑
Laravel的latestOfMany确实仅支持hasOne和morphOne关联,但我们可以通过手动构建子查询约束来实现hasOneThrough下获取关联模型最新记录的需求。
问题分析
你给出的直接在hasOneThrough上调用->ofMany('created_at', 'MAX')的写法无法得到正确结果,因为Laravel会忽略中间表B的关联约束,最终取的是全局所有C记录中created_at最大的那条,而不是当前A模型关联的B对应的C记录中的最大值。
可行解决方案
方案1:子查询筛选最新记录
通过嵌套子查询,先定位到当前A关联的所有C中最新的那条记录的ID,再关联到C模型:
// A.php public function latestC() { return $this->hasOneThrough(C::class, B::class) ->whereIn('c.id', function ($query) { $query->selectRaw('MAX(c.id)') ->from('b') ->join('c', 'b.id', '=', 'c.b_id') ->whereColumn('b.a_id', 'a.id') ->groupBy('b.a_id'); }); }
如果存在多条C记录created_at相同的情况,用MAX(c.id)作为兜底可以保证唯一结果,避免返回多条记录。
方案2:链式关联+latestOfMany
如果需求允许,也可以拆分关联:先在B模型中定义获取最新C的hasOne关联,再在A模型中通过hasOneThrough关联这个最新的C(此方案取的是每个B的最新C中,属于A的所有C里的最新一条):
// B.php public function latestC() { return $this->hasOne(C::class)->latestOfMany(); } // A.php public function latestC() { return $this->hasOneThrough( C::class, B::class, 'a_id', // B表关联A表的外键 'id', // C表关联B表的外键 'id', // A表的主键 'id' // B表的主键 )->latestOfMany('created_at'); }
方案3:自定义ofMany约束
直接在hasOneThrough中给ofMany方法传入闭包,补充中间表的关联约束:
// A.php public function latestC() { return $this->hasOneThrough(C::class, B::class) ->ofMany( ['created_at' => 'MAX', 'id' => 'MAX'], function ($query) { // 补充中间表B的关联条件,确保只查询当前A对应的B下的C $query->join('b', 'c.b_id', '=', 'b.id') ->whereColumn('b.a_id', 'a.id'); } ); }
以上三种方案都可以实现hasOneThrough关联下获取最新记录的效果,你可以根据实际业务场景选择最合适的写法。
内容的提问来源于stack exchange,提问作者Erich
相关产品推荐
相关产品推荐

