Laravel中使用Yajra Datatables关联获取采购表名称问题
解决Laravel关联查询并在Yajra Datatables展示关联字段的问题
首先修正模型中的错误关联:Sales模型无需直接关联Purchase,因为Sales是通过Product间接关联到Purchase的,建议删除Sales模型里的purchase()方法,避免逻辑混淆。
步骤1:优化查询语句,预加载关联数据
原查询仅获取Sales表数据,现在通过with()预加载Product及其关联的Purchase,同时指定所需字段,减少不必要的数据查询,避免N+1问题:
$sales = Sales::select('id', 'product_id', 'quantity', 'total-price') // 只选取需求中的字段 ->whereBetween(DB::raw('DATE(created_at)'), [$from_date, $to_date]) ->with(['product' => function ($query) { // 预加载Product时,同时获取关联Purchase的name字段 $query->select('id', 'purchase_id')->with(['purchase' => function ($q) { $q->select('id', 'name'); }]); }]) ->get();
通过嵌套with()实现Sales → Product → Purchase的关联预加载,仅拉取需要的字段,提升查询效率。
步骤2:调整Yajra Datatables列配置
在Datatables中定义对应列,将关联的Purchase的name字段展示出来:
return Datatables::of($sales) ->addIndexColumn() // 自定义关联字段列 ->addColumn('name', function ($sale) { // 用可选链式调用避免关联为空时报错,空值显示默认文本 return $sale->product?->purchase?->name ?? '无'; }) ->rawColumns(['name']) ->make(true);
如果你的PHP版本低于8.0,不支持?->可选链式调用,可以用optional()函数替代:
return optional(optional($sale->product)->purchase)->name ?? '无';
完整控制器代码示例
use App\Models\Sales; use Illuminate\Support\Facades\DB; use Yajra\DataTables\Facades\DataTables; public function getSalesData($from_date, $to_date) { $sales = Sales::select('id', 'product_id', 'quantity', 'total-price') ->whereBetween(DB::raw('DATE(created_at)'), [$from_date, $to_date]) ->with(['product' => function ($query) { $query->select('id', 'purchase_id')->with(['purchase' => function ($q) { $q->select('id', 'name'); }]); }]) ->get(); return Datatables::of($sales) ->addIndexColumn() ->addColumn('name', function ($sale) { return $sale->product?->purchase?->name ?? '无'; }) ->rawColumns(['name']) ->make(true); }
关键注意点
- 预加载关联时必须指定字段,否则会查询该表所有字段,影响性能。
- 确保Product模型的
purchase()关联外键正确:默认使用purchase_id,与表结构匹配,无需额外指定。
内容的提问来源于stack exchange,提问作者zuma boy
相关产品推荐
相关产品推荐

