【问题标题】:Using Nested Intermediate Tables使用嵌套中间表
【发布时间】:2013-12-20 00:54:17
【问题描述】:

我正在使用 Laravel 4 并尝试设置一个表结构来处理以下问题。

  • 我有 3 张桌子:球员、球队和赛季
  • 对于每个赛季,我将分配多支球队,每支球队将分配多名球员。
  • 我需要维护每个赛季的历史数据,因此我不能直接连接表格,因为更改基础球员/球队表格会以这种方式影响所有赛季。

我使用中间表 teams_in_season 连接了 Seasons -> Teams 表,如下所示:

class Season extends \Eloquent
{
    public function teams()
    {
        return $this->belongsToMany('Team', 'teams_in_season');
    }
}

按预期工作。当我想设置玩家分配时,问题就来了。自然地,我想将球队与球员联系起来,所以我的思路是我需要从另一个中间表创建一个中间表。例如:

seasons -> teams_in_season -> players_in_teams -> players

如果我选择 Seasons -> Players,那将可行,只是我无法以这种方式急切加载它。

seasons -> players_in_season -> players

$season->teams->players->get();

本质上,用户输入数据的方式是创建赛季、分配球队、将球员分配到球队,然后最终添加得分。所有输入的数据都需要维护,因此需要中间表。

所以,这是我的问题:

  1. 我可以这样嵌套/链接中间表吗?
  2. 有没有更好的方法可以设置我想要实现的目标?

【问题讨论】:

    标签: orm laravel laravel-4 eloquent eager-loading


    【解决方案1】:

    这是一个难题。您需要将球员与球队和赛季之间的数据透视表相关联。出于这个原因,我可能会将其设置为它自己的模型。

    关系

    • Season hasMany SeasonTeam
    • SeasonTeam belongsTo Team
    • SeasonTeam belongsToMany Player

    急切加载

    这是您如何使用严格的关系方法和预先加载列出所有球队及其球员名单的方法。这是 4 个查询。

    $season = Season::with('seasonTeams.players', 'seasonTeams.team')->find(1);
    
    foreach ($season->seasonTeams as $seasonTeam)
    {
        echo $seasonTeam->team->name;
    
        foreach ($seasonTeam->players as $player)
        {
            echo $player->name;
        }
    }
    

    加入

    我不会在这里详细说明,但您也可以使用查询构建器中的联接来提取在给定赛季中属于球队成员的球员。查看下面的链接。

    http://four.laravel.com/docs/queries#joins

    【讨论】:

    • @Colin - 感谢您的快速回复。我正在修改我的代码,看看这是否对我有用。使用此方法,您拥有属于 Players 表的 SeasonTeam,但由于我还需要实例化球员,您是否建议我在 SeasonTeam 和 Players 之间创建另一个 Pivot 表(例如,我们将其称为 SeasonPlayers)?跨度>
    • 是的,belongsToMany 关系使用两个实体之间的数据透视表。您不需要模型来表示它,但您可以。 SeasonTeam 有点不正常,但我认为在这种情况下这是一个很好的解决方案。这些是我想到的表格:seasons、seasonteams、teams、players、player_seasonteam
    【解决方案2】:

    我尝试了一些不同的想法(包括 Colin 的回答),但决定在这里走一条不同的路线。主要是我觉得使用$season->seasonTeams->teams() 有点难读。此外,尝试将一个中间表与另一个中间表链接起来也感觉有点奇怪。我想出的解决方案是这样的:

    对于团队,我保留了我最初的季节设计 -> teams_in_seasons -> teams,这使我可以使用 $season->teams() 查找实例化团队,并使用以下季节模型的关系来查找其中所需的任何枢轴数据:

    public function teams()
    {
        return $this->belongsToMany('Team', 'teams_in_season');
    }
    

    反之亦然:

    public function seasons()
    {
        return $this->belongsToMany('Season', 'teams_in_season');
    }
    

    对于球员,我决定将数据透视表players_in_teams 连接到季节表和球队表,而不是链接到现有的数据透视表teams_in_season。为了将这些连接在一起,我决定使用查询构建器在 Team 模型上构建我自己的查询,如下所示:

    public function players($season_id, $team_id)
    {
        return DB::table('players')
            ->select(DB::raw('players.*'))
            ->join('players_in_team', 'players.id', '=', 'players_in_team.player_id')
            ->where('season_id', '=', $season_id)
            ->where('team_id', '=', $team_id)
            ->orderBy('last_name');
    }
    

    这将允许我为给定赛季球队急切加载球员,如下所示:

    $team->players($season->id, $team->id)->get()
    

    这可能有点不正统,但它对我的目的很有效。我找不到另一种在逻辑上对我有意义的方法。它还具有允许我向季节模型添加一个方法的副作用,该方法允许我急切加载给定季节的所有玩家,例如:

    Season::find(1)->players
    

    【讨论】:

    • 您无需做太多工作就可以将其恢复到正常的日常生活中。 Season::players() 和 Team::players() 都是 $this->hasMany('Player')。除此之外,看看使用范围将其中的一些封装到自定义查询构建器方法中。 laravel.com/docs/eloquent#query-scopes Player::season(1)->team(5)->get();赛季::find(1)->players()->team(5)->get();
    • 有趣,我还没有阅读范围,但我认为这是这里缺少的部分。把它和我选择的方法结合起来听起来真的很棒。再次感谢!
    猜你喜欢
    • 2018-01-06
    • 1970-01-01
    • 1970-01-01
    • 2015-03-13
    • 1970-01-01
    • 1970-01-01
    • 2013-12-11
    • 2019-10-08
    • 1970-01-01
    相关资源
    最近更新 更多