You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Eloquent:如何在查询中添加属性而非模型中?

最优实现方案

方法一:数据库层面直接计算(推荐,支持排序)

直接通过查询构建器在数据库层面统计订单数量,所有操作一次完成,性能最优且天然支持排序:

// 直接调用查询构建器
$customers = Customer::selectRaw('customers.*, (SELECT COUNT(*) FROM orders WHERE orders.customer_id = customers.id) as orders_nb')
    ->orderBy('orders_nb')
    ->get();

如果需要复用该逻辑,可以封装成本地作用域,让调用更符合Eloquent链式风格:

class Customer extends Eloquent {
    // 定义本地作用域
    public function scopeWithOrdersCount($query)
    {
        return $query->selectRaw('customers.*, (SELECT COUNT(*) FROM orders WHERE orders.customer_id = customers.id) as orders_nb');
    }
}

// 调用方式
$customers = Customer::withOrdersCount()->orderBy('orders_nb')->get();

该方式优势:

  • 仅执行1次数据库查询,避免N+1性能问题
  • 原生支持orderBy('orders_nb')进行数据库层面排序
  • 仅在主动调用该作用域时才添加字段,不会全局生效

方法二:集合映射(适合无需数据库排序的场景)

如果不需要在数据库层面排序,可利用Eloquent集合的map方法简化代码,同时通过with预加载关联避免N+1查询:

$customers = Customer::with('orders')->get()->map(function ($customer) {
    $customer->orders_nb = $customer->orders->count();
    // 可选:隐藏关联的orders字段,减少冗余返回数据
    $customer->setHidden(array_merge($customer->getHidden(), ['orders']));
    return $customer;
});

注意:这种方式是在内存中计算数量,无法直接用orderBy('orders_nb')做数据库排序,若需排序需在集合层面操作:

$sortedCustomers = $customers->sortBy('orders_nb');

对比原方案的优化点

原方案未预加载orders关联,会触发N+1查询导致性能低下;上述两种方法:

  • 方法一在数据库层完成统计,性能最优且支持排序
  • 方法二用集合映射简化代码,同时通过预加载避免了N+1问题

内容的提问来源于stack exchange,提问作者Totuxx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 08:45:31