laravel 关联查询 laravel查询数据库
论文探讨Laravel Yajra DataTables处理在关联模型数据时的常见问题,特别是关系列排序错误和动作列中ID冲突的挑战。通过详细分析与连接的区别文章,提出了一种高效且可靠的解决方案,即利用SQL JOIN操作并配合列别名,确保关联数据正确排序并获取准确的行ID,从而优化数据表的显示与交互体验。
在使用laravel yajra 数据表构建复杂的数据列表时,开发者经常会遇到需要显示和排序关联模型数据的情况。然而,直接使用 eloquent 的 with() 方法进行关联加载,并尝试对关联字段进行排序或在自定义列(如操作列)中获取主表 id 时,可能会遇到“列未找到”的错误或 id 错乱的问题。理解问题来源:with() 与 JOIN 的差异
Laravel Eloquent的with()方法用于实现“预加载”(Eager Loading),它会执行额外的SQL查询来获取关联数据,然后将这些数据“注入”到主模型实例中。这种方式减少了N 1 查询问题,但在 Yajra DataTables的上下文环境中,它并没有将关联表直接JOIN到主查询中。,因此当DataTable尝试对一个未通过JOIN引入的关联列进行排序时,数据库会报告该列不存在,因为主查询中确实没有这个列。
同时,在action列等自定义列的回调函数中,如果DataTable的eloquent($query)方法没有明确指定选择主表的全部列(例如kabupaten.*),或者在query()方法中进行了隐式的列选择,可能导致传递给视图的$id指针指向关联表的ID而不是主表的ID,造成数据操作混乱。 解决方案:使用JOIN操作与列别名
解决上述问题的关键在于,明确地在DataTable的query()方法中使用SQL JOIN语句将关联表连接进来,并为关联列设置一个唯一的别名,以便DataTable能够识别并对其进行排序。同时,确保显式选择主表的所有列,表示ID不一致。 1. 修改query()方法
将KabupatenDataTable中的query()方法从使用with()改为使用leftJoin()。leftJoin确保即使匹配的关联数据,主表的数据也能被。通过addSelect()方法,我们显式地选择了kabupaten表的所有列(kabupaten.*),以及provinsi表的provinsi列,并明确指定了别名provinsi_provinsi。
lt;?phpnamespace App\DataTables;使用 App\Models\Kabupaten;使用 Yajra\DataTables\Html\Button;使用 Yajra\DataTables\Html\Column;使用 Yajra\DataTables\Services\DataTable;class KabupatenDataTable extends DataTable{/** * 构建 DataTable 类。* * @param mix $query 来自 query() 方法的结果。 * @return \Yajra\DataTables\DataTableAbstract */ public function dataTable($query) { return datatables() -gt;eloquent($query) -gt;addIndexColumn() -gt;addColumn('kordinat', function(Kabupaten $kabupaten) { // 的这里 $kabupaten 对象现在包含通过 JOIN 获取的 provinsi 属性 return $kabupaten-gt;koordinat_bujur . quot;,quot; . $kabupaten-gt;koordinat_lintang; }) -gt;addColumn('action', 'kabupaten.action'); } /** * 获取数据表的查询源。 * * @param \App\Models\Kabupaten $model * @return \Illuminate\Database\Eloquent\Builder */ public function query(Kabupaten $model) { // 使用 leftJoin 显式连接 provinsi 表 return Kabupaten::query() -gt;leftJoin('provinsi', 'provinsi.id', '=', 'kabupaten.provinsi_id') -gt;addSelect([ 'kabupaten.*', //确保选择kabupaten表的所有列,包括其ID 'provinsi.provinsi as provinsi_provinsi' // 为关联列设置别名]); } /** * 如果你想使用html builder,可选方法。 *
* @return \Yajra\DataTables\Html\Builder */ public function html() { return $this-gt;builder() -gt;setTableId('kabupaten-table') -gt;columns($this-gt;getColumns()) -gt;minifiedAjax() -gt;dom('Bfrtip') -gt;orderBy(1) // 根据实际列顺序调整 -gt;parameters([ 'buttons' =gt; ['excel'], ]) -gt;buttons( Button::make('create'), Button::make('export'), Button::make('print'), Button::make('reset'), Button::make('reload') ); } /** * 获取列。 * * @return array */ protected function getColumns() { return [ Column::make('DT_RowIndex')-gt;title('No')-gt;orderable(false)-gt;searchable(false), //使用别名定义列,并设置名称属性以支持排序 Column::make('provinsi_provinsi')-gt;name('provinsi_provinsi')-gt;title('Provinsi'),列::make('status'), 列::make('kabupaten')-gt;title('Nama kabupaten'), 列::make('ketinggian'), 列::make('kordinat') -gt;exportable(false) -gt;printable(false), 列::compulated('action') -gt;exporta
ble(false) -gt;printable(false), ]; } /** * 获取导出文件名。 * * @return string */ protected function filename() { return 'Kabupaten_' . date('YmdHis'); }}登录后复制2. 更新 getColumns() 方法
在 getColumns() 方法中,将原来的 Column::make('provinsi.provinsi') 改为使用我们为关联列设置的别名,并通过 name() 方法明确指定用于排序的列名,这必须与 addSelect 中定义的别名一致。// ... (在 KabupatenDataTable 类的 getColumns 方法中)protected function getColumns(){ return [ Column::make('DT_RowIndex')-gt;title('No')-gt;orderable(false)-gt;searchable(false), // 使用别名定义列,并设置名称属性以支持排序 Column::make('provinsi_provinsi')-gt;name('provinsi_provinsi')-gt;title('Provinsi'), Column::make('status'),栏目::make('kabupaten')-gt;title('Nama kabupaten'), 列::make('ketinggian'), 列::make('kordinat') -gt;exportable(false) -gt;printable(false), 列::compulated('action') -gt;exportable(false) -gt;printable(false), ];}登录后复制3. 保证action列正确获取ID
由于我们在query()方法中使用了addSelect(['kabupaten.*',...]),Yajra DataTables在处理每一行数据时,会优先使用主模型(Kabupaten)的相应属性。,在kabupaten.action视图中,$id变量将正确指向kabupaten.id,而不是provinsi.id。
{{-- resources/views/kabupaten/action.blade.php --}}lt;form id="delete_form";method="POST";gt;@csrf @method('DELETE')lt;/formgt;lt;a type="button";href="{{route('adm.kabupaten.show',['id' =gt;$id])}}quot;class="btn btn-just-icon btn-round btn-sm btn-info";data-toggle="tooltip";data-placement="bottom";title="detail";gt;lt;i class="fa fa-eye";gt;lt;/igt;lt;/agt;lt;a href="{{route('adm.kabupaten.edit',['id' =gt;$id])}}quot; class=“;btn btn-just-icon btn-round btn-sm btn-primary”; data-toggle=“;tooltip”; data-placement=“;bottom”; title=“;ubah”;gt; lt;i class=“;fa fa-edit”;gt;lt;/igt;lt;/agt;lt;a href=“;#”; data-url=“;{{ route('adm.kabupaten.destroy', $id) }}”; class=“;btn btn-just-icon btn-round btn-sm btn-danger”; onclick=“;return deleteConfirm(this)”;gt; lt;i class=“;fa fa-trash”;gt;lt;/igt;lt;/agt;lt;scriptgt; $(function() { $('[data-toggle=quot;tooltipquot;]').tooltip(); })lt;/scriptgt;登录后复制
这里视图中,$id将始终是kabupaten模型的ID。注意事项与最佳实践选择JOIN类型:leftJoin:保留左表(主表)的所有,即使右表(关联表)没有匹配项。innerJoin:只返回两表都有匹配项的记录。根据业务需求选择合适的JOIN类型。显式选择列:始终使用addSelect()并显式指定要记录的列,尤其是主表名.*,这样有助于避免列冲突和ID不一致查询。对于关联表的列设置清晰的别名,可以避免与主表的列名冲突,并提高代码的吸引力。性能考量:对于非常大的数据集和复杂的JOIN操作,可能会影响查询性能。确保数据库索引已正确设置在JOIN键和排序列上。
按钮关联:需要显示和排序多个关联模型的数据,可以链调用leftJoin()和addSelect()来引入更多表和列。
通过上述方法,您可以有效地解决Laravel Yajra DataTables中关联列排序失败和ID获取不准确的问题,从而构建出功能完善且性能可靠的数据表格。
以上就是Laravel Yajra DataTables关系列排序与ID获取最佳实践的详细内容,更多请关注乐哥常识网其他相关文章!