Laravel API:如何通过Resource获取beasiswas与mitras关联数据?
问题:Eloquent关联beasiswas与mitras表时的列重复及识别错误
我在YouTube上学了用Eloquent从数据库返回数据的教程,基础功能能正常运行,但不知道怎么关联beasiswas表的外键和mitras表的主键。在Resource文件里尝试引入表模型时,系统提示两表的「id」列名称重复;指定beasiswas.id和mitras.id区分时,又提示无法识别「beasiswas」。
我的代码
App\Http\Resources\V1\BeasiswaResource
<?php namespace App\Http\Resources\V1; use App\Models\Beasiswa; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; class BeasiswaResource extends JsonResource { /** * Transform the resource into an array. * * @return array<string, mixed> */ public function toArray(Request $request): array { $beas = Beasiswa::join('mitras','beasiswas.id','=','mitras.id')->get(); return [ 'idBeasiswa'=>$beas->beasiswas.id, 'idMitra'=>$beas->id_mitra, 'deskripsi'=>$beas->deskripsi, 'angkatanAwal'=>$beas->angkatan_awal, 'angkatanAkhir'=>$beas->angkatan_akhir, 'semMin'=>$beas->sem_min, 'semMax'=>$beas->sem_max, 'status'=>$beas->status ]; } }
App\Http\Controllers\Api\V1\BeasiswaController
<?php namespace App\Http\Controllers\Api\V1; use App\Models\Beasiswa; use App\Http\Controllers\Controller; use App\Http\Requests\StoreBeasiswaRequest; use App\Http\Requests\UpdateBeasiswaRequest; use App\Http\Resources\V1\BeasiswaResource; use App\Http\Resources\V1\BeasiswaCollection; class BeasiswaController extends Controller { /** * Display a listing of the resource. */ public function index() { return new BeasiswaCollection(Beasiswa::paginate()); } ...
解决方案
你当前的写法存在几个核心问题:
- 在Resource的
toArray方法里直接执行Beasiswa::join()->get()完全错误——Resource本身是接收已查询完成的模型实例/集合,不需要重新发起数据库查询,而且get()返回的是模型集合,不是单个模型,直接调用$beas->beasiswas.id会触发语法错误。 - 手动用
join硬关联会导致列名冲突,Eloquent的关联模型才是处理表关联的标准方式,无需手动编写join语句。
步骤1:给Beasiswa模型定义关联关系
打开App\Models\Beasiswa,添加关联方法(假设beasiswas表的外键是id_mitra,关联mitras表的id主键):
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; class Beasiswa extends Model { // 定义与Mitra模型的关联 public function mitra(): BelongsTo { return $this->belongsTo(Mitra::class, 'id_mitra', 'id'); } }
步骤2:修改BeasiswaResource
Resource直接使用当前资源的属性和关联关系,不需要重新查询数据库:
<?php namespace App\Http\Resources\V1; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; class BeasiswaResource extends JsonResource { public function toArray(Request $request): array { // Resource接收的是单个Beasiswa模型实例,直接用$this访问属性和关联 return [ 'idBeasiswa' => $this->id, // 此处即为beasiswas表的id 'idMitra' => $this->id_mitra, 'deskripsi' => $this->deskripsi, 'angkatanAwal' => $this->angkatan_awal, 'angkatanAkhir' => $this->angkatan_akhir, 'semMin' => $this->sem_min, 'semMax' => $this->sem_max, 'status' => $this->status, // 如果需要返回mitra的详细信息,可以添加以下代码(需先创建MitraResource) // 'mitra' => new MitraResource($this->whenLoaded('mitra')) ]; } }
步骤3:优化控制器,预加载关联(可选但推荐)
为了避免N+1查询问题(每个Beasiswa实例单独查询一次mitra表),在控制器里预加载关联:
public function index() { // 用with预加载mitra关联 return new BeasiswaCollection(Beasiswa::with('mitra')->paginate()); }
关于之前报错的原因
- 你在Resource里执行
Beasiswa::join()->get()得到的是模型集合,不是单个模型,所以$beas->beasiswas.id完全不符合语法,集合不存在beasiswas这个属性。 - 手动使用
join时,若两张表都有id列,查询结果中的id会被后一张表的id覆盖,需要用select指定别名(比如Beasiswa::join('mitras','beasiswas.id_mitra','=','mitras.id')->select('beasiswas.id as beasiswa_id', 'mitras.id as mitra_id', ...)->get()),但这并非Eloquent的推荐用法,使用关联模型才是更规范的实现方式。
内容的提问来源于stack exchange,提问作者ichinisanshi
相关产品推荐
相关产品推荐

