如何复用Eloquent Builder两次获取结果?Laravel 9查询异常求助
问题原因
Eloquent Builder实例是**可变(Mutable)**的,和CarbonImmutable的不可变特性完全不同。你每次调用where、whereDate这类查询方法时,都会直接修改原Builder对象的查询条件,而非返回全新的实例。
所以第一次执行$expenses->whereDate('txn_date', '<', $start)->sum()时,txn_date < $start这个条件已经被追加到原$expenses实例中。后续再调用whereDate('txn_date', '>=', $start)时,最终的查询条件会变成:
WHERE contractor_id = ? AND txn_date < ? AND txn_date >= ? AND txn_date <= ?
时间条件互斥,自然返回空集合。而直接赋值$olderDebits = $expenses只是传递引用,并没有创建新的Builder实例,修改$olderDebits的条件本质还是在修改原$expenses。
解决方案
要复用基础查询逻辑,必须用clone关键字创建Builder实例的独立副本,这样每个副本的条件修改都不会影响原实例和其他副本:
// 构建基础查询 $expenses = PropertyExpense::with(['bill']) ->where('contractor_id', $supplier); // 克隆副本用于计算期初余额 $oldDebitsQuery = clone $expenses; $oldDebits = $oldDebitsQuery->whereDate('txn_date', '<', $start) ->sum('billed'); // 原实例用于查询时间段数据,不受之前的条件影响 $debits = $expenses ->whereDate('txn_date', '>=', $start) ->whereDate('txn_date', '<=', $end) ->get();
也可以简化写法,每次直接克隆原实例确保查询独立:
$baseQuery = PropertyExpense::with(['bill'])->where('contractor_id', $supplier); $oldDebits = (clone $baseQuery)->whereDate('txn_date', '<', $start)->sum('billed'); $debits = (clone $baseQuery)->whereBetween('txn_date', [$start, $end])->get();
注:用whereBetween可以替代两个whereDate条件,让代码更简洁。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

