Laravel Eloquent 关系 - 表的多列引用相同的外键

Posted

技术标签:

【中文标题】Laravel Eloquent 关系 - 表的多列引用相同的外键【英文标题】:Laravel Eloquent relationship - multiple columns of table reference same foreign key 【发布时间】:2021-07-05 17:10:45 【问题描述】:

Laravel/Eloquent 新手在这里。我正在实现一个简单的棋盘游戏。每场比赛有4名玩家。表结构由一个 Players 表和一个 Games 表组成:

SELECT * FROM players;

id    | name        |
---------------------
1     | John        |
2     | Mary        |
3     | Linda       |
4     | Alex        |
5     | Chris       |
6     | Ron         |
7     | Dave        |
SELECT * FROM games;

id    | player1_id  | player2_id  | player3_id    player4_id  
---------------------------------------------------------------------
1     | 1           | 2           | 3           | 4
2     | 3           | 5           | 6           | 7
3     | 2           | 3           | 5           | 6
4     | 2           | 4           | 5           | 7

目标:我希望能够获得玩家参与过的所有游戏。

为此,我尝试在 Player 模型中编写一个函数 games()。对于 id 为 2 的玩家,这应该返回游戏 1、3、4 / 对于 id 为 3 的玩家,它应该返回游戏 1、2、3 等等。

使用原始 SQL 我会做这样的事情:

SELECT * FROM games WHERE 
  (player1_id = 2 OR player2_id = 2 OR player3_id = 2 OR player4_id = 2)

但是对于 Eloquent,我很难弄清楚必须如何建立这种关系才能实现这一目标。

同样,我也希望能够做相反的事情 - 返回游戏的所有玩家 - 在 Game 模型中使用函数 players()

模型:

// Models/Player.php

//...

class Player extends Model

    public function games()

        //?

    

// Models/Game.php

//...

class Game extends Model

    public function players()

        //?

    

【问题讨论】:

这是一个 N 到 N 的关系,你必须规范化。 DB::table('games')->where('player1_id', '=', id)->orwhere('player2_id', '=', 'id')->orwhere('player3_id', '=', 'id')->orwhere('player4_id', '=', 'id')->get(); @HassaanAli 不!!!!!!使用关系,停止DB::something,认为DB::something不存在简单的操作!!!!!!!!! 我同意。这不是公约。但为简单起见,解决方案就在那里。 :) 【参考方案1】:

在不更改数据库结构的情况下,您可以误用hasMany 声明来获取所有 4 名玩家。

class Game extends Model

    public function players()
    
        return $this->hasMany(Player::class, 'id', 'player1_id')
                    ->orWhere('id', $this->player2_id)
                    ->orWhere('id', $this->player3_id)
                    ->orWhere('id', $this->player4_id);
    

class Player extends Model

    public function games()
    
        return $this->hasMany(Game::class, 'player1_id', 'id')
                    ->orWhere('player2_id', $this->id)
                    ->orWhere('player3_id', $this->id)
                    ->orWhere('player4_id', $this->id);
    

但这并不理想。

您应该有第三个表来正确映射这种多对多关系。

table 1 - players:     id (pk), name
table 2 - games:       id (pk)
table 3 - game_player: id (pk), game_id (fk), player_id (fk), unique([game_id, player_id])
class Game extends Model

    public function players()
    
        return $this->belongsToMany(Player::class, 'game_player');
    

class Player extends Model

    public function games()
    
        return $this->belongsToMany(Game::class, 'game_player');
    

【讨论】:

这实际上正是我想要的。诚然,更合适的解决方案(以及更好的设计)确实是使用数据透视表进行数据库规范化。然而,为了简化每场比赛一个记录的设计,我很可能会选择这种方法。非常感谢。

以上是关于Laravel Eloquent 关系 - 表的多列引用相同的外键的主要内容,如果未能解决你的问题,请参考以下文章

Laravel eloquent 检查不存在的多对多关系

Laravel Eloquent 多列 IN 子句

没有关系的表的 Laravel Eloquent 关系问题

Laravel Eloquent 表之间通过其他表的关系

Eloquent 中与分类学的多对多关系

Laravel Eloquent 关系 - 表的多列引用相同的外键