Laravel 9 多对多关系:如何展示用户选中的游戏?
问题描述
我有Users、Videogames和用户游戏关联表三张数据表,想要实现展示用户选中的游戏的功能,但当前效果不符合预期。以下是相关代码,请帮忙解决:
控制器代码
public function users() { $videogamesBuilder = VideoGames::with(['plataforma', 'generos', 'categoria', 'numJugadores', 'users']); $users = DB::table('users')->select('user_id', 'nombre', 'email','rol_usuario')->get(); $videogames = $videogamesBuilder->paginate(4)->withQueryString(); return view('admin.videojuegos.users', [ 'videogames' => $videogames, 'users' => $users, ]); }
User模型代码
class User extends User { use HasApiTokens, Notifiable; protected $table = 'users'; protected $primaryKey = 'user_id'; protected $fillable = [ 'email', 'nombre', 'password', 'rol_usuario']; protected $hidden = ['password', 'remember_token']; public const VALIDATE_RULES = [ 'email' => 'required', 'nombre' => 'required|min:5', 'password' => 'required|numeric|min:0', 'rol_usuario' => 'required', ]; }
Videogame表迁移文件
class CreateVideojuegosTable extends Migration { public function up() { Schema::create('videogames', function (Blueprint $table) { $table->id('videogame_id'); $table->string('titulo', 300); $table->text('subtitulo'); $table->timestamps(); }); } public function down() { Schema::dropIfExists('videogames'); } }
Users表迁移文件
return new class extends Migration { public function up() { Schema::create('users', function (Blueprint $table) { $table->id('user_id'); $table->string('email')->unique(); $table->string('nombre'); $table->string('password'); $table->string('rol_usuario'); $table->rememberToken(); $table->timestamps(); }); } public function down() { Schema::dropIfExists('users'); } };
用户选中游戏关联表迁移文件
return new class extends Migration { public function up() { Schema::create('videojuegos_tienen_usuarios', function (Blueprint $table) { $table->foreignId('videogames_id')->constrained('videogames', 'videogames_id'); $table->unsignedBigInteger('user_id'); $table->foreign('user_id')->references('user_id')->on('users'); $table->primary(['videogames_id', 'user_id']); $table->timestamps(); }); } public function down() { Schema::dropIfExists('videojuegos_tienen_usuarios'); } };
关联表数据填充文件
class VideojuegosTienenUsuariosSeeder extends Seeder { public function run() { \DB::table('videojuegos_tienen_usuarios')->insert([ [ 'videojgame_id' => 1, 'user_id' => 1, 'created_at' => now(), 'updated_at' => now(), ], [ 'videojgame_id' => 2, 'user_id' => 1, 'created_at' => now(), 'updated_at' => now(), ], [ 'videojgame_id' => 2, 'user_id' => 2, 'created_at' => now(), 'updated_at' => now(), ], [ 'videojgame_id' => 2, 'user_id' => 3, 'created_at' => now(), 'updated_at' => now(), ], [ 'videojgame_id' => 3, 'user_id' => 1, 'created_at' => now(), 'updated_at' => now(), ] ]); } }
视图代码
<table class="table table-bordered table-striped"> <thead> <tr> <th>ID</th> <th>Nombre de usuario</th> <th>Email Usuario</th> <th>Rol del Usuario</th> </tr> </thead> <tbody> @foreach($users as $user) <tr> <td>{{ $user->user_id }}</td> <td>{{ $user->nombre }}</td> <td>{{ $user->email }}</td> <td>{{ $user->rol_usuario }}</td> @endforeach </tr> </tbody> </table>
问题分析与修复方案
1. 模型关联缺失
当前User模型和VideoGames模型未定义多对多关联,无法正确获取用户选中的游戏。
修复User模型:
class User extends Authenticatable // 修正继承类,避免递归继承 { use HasApiTokens, Notifiable; protected $table = 'users'; protected $primaryKey = 'user_id'; protected $fillable = [ 'email', 'nombre', 'password', 'rol_usuario']; protected $hidden = ['password', 'remember_token']; public const VALIDATE_RULES = [ 'email' => 'required', 'nombre' => 'required|min:5', 'password' => 'required|numeric|min:0', 'rol_usuario' => 'required', ]; // 新增多对多关联 public function videogames() { return $this->belongsToMany(VideoGames::class, 'videojuegos_tienen_usuarios', 'user_id', 'videogames_id'); } }
补充VideoGames模型定义:
class VideoGames extends Model { protected $table = 'videogames'; protected $primaryKey = 'videogame_id'; protected $fillable = ['titulo', 'subtitulo']; // 新增多对多关联 public function users() { return $this->belongsToMany(User::class, 'videojuegos_tienen_usuarios', 'videogames_id', 'user_id'); } // 保留原有plataforma、generos等关联定义 }
2. Seeder字段错误
Seeder中使用videojgame_id,但关联表实际字段为videogames_id,导致数据无法正确插入:
修复Seeder:
class VideojuegosTienenUsuariosSeeder extends Seeder { public function run() { \DB::table('videojuegos_tienen_usuarios')->insert([ [ 'videogames_id' => 1, // 修正字段名 'user_id' => 1, 'created_at' => now(), 'updated_at' => now(), ], [ 'videogames_id' => 2, // 修正字段名 'user_id' => 1, 'created_at' => now(), 'updated_at' => now(), ], [ 'videogames_id' => 2, // 修正字段名 'user_id' => 2, 'created_at' => now(), 'updated_at' => now(), ], [ 'videogames_id' => 2, // 修正字段名 'user_id' => 3, 'created_at' => now(), 'updated_at' => now(), ], [ 'videogames_id' => 3, // 修正字段名 'user_id' => 1, 'created_at' => now(), 'updated_at' => now(), ] ]); } }
3. 控制器数据查询优化
当前用DB门面查询用户,无法直接通过模型关联获取游戏,改为使用User模型预加载关联:
修复控制器:
public function users() { // 预加载用户关联的游戏,避免N+1查询 $users = User::with('videogames')->select('user_id', 'nombre', 'email','rol_usuario')->get(); return view('admin.videojuegos.users', [ 'users' => $users, ]); }
4. 视图未展示用户选中的游戏
当前视图仅展示用户基本信息,需添加游戏列:
修复视图:
<table class="table table-bordered table-striped"> <thead> <tr> <th>ID</th> <th>Nombre de usuario</th> <th>Email Usuario</th> <th>Rol del Usuario</th> <th>Juegos Seleccionados</th> <!-- 新增列 --> </tr> </thead> <tbody> @foreach($users as $user) <tr> <td>{{ $user->user_id }}</td> <td>{{ $user->nombre }}</td> <td>{{ $user->email }}</td> <td>{{ $user->rol_usuario }}</td> <td> @foreach($user->videogames as $game) <span>{{ $game->titulo }}</span>@if(!$loop->last), @endif @endforeach </td> </tr> @endforeach </tbody> </table>
内容的提问来源于stack exchange,提问作者designArg
相关产品推荐
相关产品推荐

