Laravel中两个外键关联同表主键的递归关系实现及报错解决
问题根源
1066报错的核心原因是同一条SQL语句内两次关联items表时未指定不同别名,数据库无法区分两个关联的items表实例。除此之外你的模型关联定义存在几处错误,调整后无需手动写JOIN语句,用Eloquent关联实现需求更简洁。
第一步:修正ItemAssociation模型关联
protected $table = 'item_associations'; // 对应第一个外键item_id的关联 public function item() { return $this->belongsTo(\App\Models\Item::class, 'item_id'); } // 对应第二个外键item2_id的关联,不要用字段名当方法名,避免属性和方法调用冲突 public function relatedItem() { // belongsTo第三个参数是父表主键,默认就是id,无需额外传参 return $this->belongsTo(\App\Models\Item::class, 'item2_id'); }
第二步:修正Item模型关联
原关联指向了错误的UserType类,同时需要分别定义两个方向的关联,对应自己作为item_id和item2_id的场景:
protected $table = 'items'; // 作为主物品的关联关系 public function outgoingAssociations() { return $this->hasMany(\App\Models\ItemAssociation::class, 'item_id'); } // 作为被关联物品的关联关系 public function incomingAssociations() { return $this->hasMany(\App\Models\ItemAssociation::class, 'item2_id'); }
第三步:控制器查询代码调整
推荐用Eloquent预加载实现,避免N+1查询问题,也不用处理表别名冲突:
// 预加载两个关联的物品数据 $itemAssociations = \App\Models\ItemAssociation::with(['item', 'relatedItem'])->get(); return view('welcome', compact('itemAssociations'));
如果你确实需要手写JOIN查询,给items表加不同别名即可解决报错:
$itemAssociations = DB::table('item_associations') ->join('items as item1', 'item_associations.item_id', '=', 'item1.id') ->join('items as item2', 'item_associations.item2_id', '=', 'item2.id') // 手动指定查询字段别名,避免同名字段覆盖 ->select('item_associations.id as assoc_id', 'item1.name as item1_name', 'item2.name as item2_name') ->get();
第四步:Blade模板渲染
直接遍历关联数据即可实现你要的物品关联展示效果,示例如下(假设items表有name字段作为物品名称):
<table border="1" cellpadding="8"> <thead> <tr> <th>关联记录ID</th> <th>物品A名称</th> <th>关联物品B名称</th> </tr> </thead> <tbody> @foreach($itemAssociations as $assoc) <tr> <td>{{ $assoc->id }}</td> <td>{{ $assoc->item->name }}</td> <td>{{ $assoc->relatedItem->name }}</td> </tr> @endforeach </tbody> </table>
内容的提问来源于stack exchange,提问作者Amir Adamov
相关产品推荐
相关产品推荐

