Laravel 关系:一个foreignKey 对应多个localKey 关系
Posted
技术标签:
【中文标题】Laravel 关系:一个foreignKey 对应多个localKey 关系【英文标题】:Laravel relationship : one foreignKey for several localKey relationship 【发布时间】:2019-06-07 07:52:08 【问题描述】:我必须使用 Laravel 开发一个 api,但我遇到了这个问题: 我需要获取所有匹配项,对于每场匹配项,我需要获取属于该匹配项的用户(每场匹配有 2 个用户)
我已经搜索了这个问题的答案,我找到了这个https://github.com/topclaudy/compoships,但它对我没有用。
到目前为止,我有这个:
class Match extends Model
protected $table = 'matchs';
public $primaryKey = 'id';
public function playerOne()
return $this->hasMany('App\User', 'id', 'playerOne_id');
public function playerTwo()
return $this->hasMany('App\User', 'id', 'playerTwo_id');
控制器方法:
public function index()
$matchs = Match::with('playerOne', 'playerTwo')->orderBy('created_at', 'asc')->get();
return $matchs;
//return new MatchsCollection($matchs);
我的数据库如下所示: (匹配表)
id | playerOne_id | playertwo_id | winner_id | status
------------------------------------------------------------
1 | 1 | 3 | 0 | PENDING
2 | 2 | 1 | 0 | PENDING
3 | 3 | 2 | 0 | PENDING
和用户表:
id | name | email
-----------------------------------
1 | John | John@email.com
2 | Mark | Mark@email.com
3 | Harry | Harry@email.com
当我调用我的 api 时,我得到了这个结果:
[
id: 1,
playerOne_id: 1,
playerTwo_id: 3,
winner_id: 0,
status: "PENDING",
created_at: "2019-01-10 00:00:00",
updated_at: null,
users: [
id: 1,
name: "John",
email: "John@email.com",
email_verified_at: null,
created_at: "2019-01-11 10:38:26",
updated_at: "2019-01-11 10:38:26"
]
,
id: 2,
playerOne_id: 2,
playerTwo_id: 1,
winner_id: 0,
status: "PENDING",
created_at: "2019-01-11 08:26:28",
updated_at: "2019-01-11 08:26:28",
users: [
id: 2,
name: "Mark",
email: "Mark@email.com",
email_verified_at: null,
created_at: "2019-01-11 10:40:13",
updated_at: "2019-01-11 10:40:13"
]
,
id: 3,
playerOne_id: 3,
playerTwo_id: 2,
winner_id: 0,
status: "PENDING",
created_at: "2019-01-11 08:45:22",
updated_at: "2019-01-11 08:45:22",
users: [
id: 3,
name: "harry",
email: "harry@email.com",
email_verified_at: null,
created_at: "2019-01-11 10:40:13",
updated_at: "2019-01-11 10:40:13"
]
]
我不想得到的是这个结果(我只是给你看第一场比赛)
[
id: 1,
playerOne_id: 1,
playerTwo_id: 3,
winner_id: 0,
status: "PENDING",
created_at: "2019-01-10 00:00:00",
updated_at: null,
users: [
id: 1,
name: "John",
email: "John@email.com",
email_verified_at: null,
created_at: "2019-01-11 10:38:26",
updated_at: "2019-01-11 10:38:26"
,
id: 3,
name: "Harry",
email: "Harry@email.com",
email_verified_at: null,
created_at: "2019-01-11 10:38:26",
updated_at: "2019-01-11 10:38:26"
]
]
这在 Laravel 中可行吗?谢谢:)
【问题讨论】:
你如何准确地调用你的 api?你是怎么查询的? 为什么不在匹配中添加两个关系Model
即 public function playerOne() return $this->hasMany(App\User::class, 'id', 'playerOne_id');
public function playerTwo() return $this->hasMany(App\User::class, 'id', 'playerTwo_id');
并使用急切加载获取它们。
@AliMrj $matchs = Match::with('users')->get();
@RossWilson $matchs = Match::with('users')->get();
@FarrukhAyyaz 我如何在我的控制器中查询/获取这个?
【参考方案1】:
为了能够将所有玩家作为user
数组的一部分返回,您可以将Match
和User
之间的关系更改为belongsToMany (many-to-many),或者在从控制器。
我建议将其更改为 BelongsToMany
,因为它在语义上更有意义,但是,我知道(取决于您到目前为止所做的工作量)它可能不实用。
您需要:
-
将
matchs
表重命名为matches
(这也意味着您可以从Match
模型类中删除protected $table = 'matchs';
。
创建一个名为match_user
的表。如果您的项目正在使用迁移,那么您可以运行:php artisan make:migration create_match_user_table --create=match_user
在该迁移中,您需要将 up()
方法的内容更改为:
public function up()
Schema::create('match_user', function (Blueprint $table)
$table->integer('match_id')->unsigned();
$table->integer('user_id')->unsigned();
$table->timestamps();
$table->primary(['match_id', 'user_id']);
);
运行php artisan migrate
在您的 Match
模型中,将 users()
关系更改为:
public function users()
return $this->belongsToMany(User::class)->withTimestamps();
如果您的表中的数据是虚拟数据,您可以跳过此步骤。否则,您需要将playerOne_id
和playertwo_id
信息移动到新的数据透视表。你可以这样做:
Match::all()->each(function ($match)
$match->users()->attach([$match->playerOne_id, $match->playertwo_id]);
);
在哪里运行它并不重要,因为它只需要运行一次,所以在你运行它之后你可以删除它。我通常会在路由或修补程序中运行它。
然后是清理工作。同样,如果您拥有的数据只是虚拟数据,那么我将删除 playerOne_id
和 playertwo_id
原始迁移,否则创建一个删除这些字段的新迁移 Dropping columns docs
完成上述操作后,您只需在控制器中执行以下操作即可获得结果:
$matches = Match::with('users')->latest()->get();
【讨论】:
以上是关于Laravel 关系:一个foreignKey 对应多个localKey 关系的主要内容,如果未能解决你的问题,请参考以下文章