【问题标题】:Eloquent relationship structure for league app联盟应用程序的雄辩关系结构
【发布时间】:2019-09-09 16:08:15
【问题描述】:

我一直在使用 Laravel REST API 开发一个 Angular 应用程序,并意识到我的关系并不像应有的那样。

我有 3 个实体 - seasonsdivisionsteams

季节:

一个赛季有很多部门,很多团队。

部门:

一个部门属于多个赛季,有多个球队。

团队:

一支球队属于多个部门,属于多个赛季。

这是因为分区可能不会用于每个赛季,球队可能会在每个赛季更换分区,或者可能不会在所有赛季中都进行比赛。

我很难理解如何实现关系逻辑。

例如,我想获取一个赛季的分区以及该分区中该特定赛季的球队,无论是当前赛季还是当用户观看旧赛季时。

这是我目前所拥有的:

季节模型

class Season extends Model
{
    protected $guarded = [];
    protected $hidden = ['pivot'];


    /**
     * Return divisions for this season
     *
     * @return BelongsToMany
     */
    public function divisions()
    {
        return $this->belongsToMany('App\Division');
    }

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

}

部门模型

class Division extends Model
{
    protected $guarded = [];

    public function matches()
    {
        return $this->hasMany('App\Fixture');
    }

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

    public function teams() {
        return $this->hasMany('App\Team');
    }

}

团队模型

class Team extends Model
{
    protected $guarded = [];
    protected $hidden = ['pivot'];

    public function division() {
        return $this->belongsTo('App\Division');
        // should be belongsToMany
    }

    public function seasons()
    {
        return $this->belongsToMany('App\Season')->select('season_id');
    }
}

有以下表格:

  • 季节
  • 部门
  • 团队
  • division_season
  • season_team

但这并不能让我在每个赛季都有一支属于不同部门的球队。

如果我将团队模型上的 division() 方法更改为 divisions() 并使用 belongsToMany() 并有一个新表 - Division_team(这是正确的方法吗?)我将如何通过他们的按赛季划分?

例如:

Get all divisions and their teams by season id

记住球队每个赛季都有可能改变分区。

编辑

根据下面 Thomas Van Der Veen 的回答,我添加了一个表 division_season_team 并在他的回答中使用了关系。

尽管尝试根据赛季 ID 与他们的球队划分分区是很困难的 - 下面会返回正确的分区,但球队不一定是当前赛季的一部分!

DivisionsController

if ($request->query('seasonId')) {
    $seasonId = $request->query('seasonId');
    return $this->respond(new DivisionCollection(Division::with('teams')->whereHas(
     'seasons', function($q) use ($seasonId) {
         $q->where('season_id', '=', $seasonId);
        })->get()
    ));
}

【问题讨论】:

  • @kerbholz 显然 HasManyThrough 不适用于多对多关系
  • 我建议多对多的关系,因为这样可以避免你的困惑
  • @AthulRaj 我正在使用多对多关系 - 查看上面提供的所有代码以及我所做的编辑 - 你在哪里看到与非多对多关系有任何关系?
  • @DJC 我认为你需要使用Many To Many (Polymorphic) Relationship
  • 是的,我仍然看到非多对多的关系。在划分模型中有两个hasMany关系。您也可以将其更改为多对多。如果所有这些模型都是多对多相关的并且具有数据透视表。我相信在你的情况下一切都会好起来的

标签: php laravel eloquent many-to-many


【解决方案1】:

通过阅读您想要的结果,一个建议是创建一个包含所有这三个关系的表。

season_division_team // Or whatever you want to call it.
id
season_id
division_id
team_id

这使您可以轻松地创建和更新关系。所有模型都可以属于许多其他模型。

您现在可以拥有的关系是:

// Season
public function divisions()
{
    return $this->belongsToMany(Division::class, 'season_division_team');
}

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

// Division
public function seasons()
{
    return $this->belongsToMany(Season::class, 'season_division_team');
}

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

// Team
public function seasons()
{
    return $this->belongsToMany(Season::class, 'season_division_team');
}

public function divisions()
{
    return $this->belongsToMany(Division::class, 'season_division_team');
}

【讨论】:

  • 这看起来很有希望 - 但是查询/关系方法是什么来获取特定赛季的所有部门及其各自的球队?我想我也不再需要 Division_season 或 season_team 表了?
  • @DJC 实际上,您不再需要旧表了。有多种方法可以检索您想要的结果。它只取决于以什么形式。您可以(懒惰地)使用withload 方法急切地加载季节上的关系。或者您可以使用whereHas 来检索相关模型。
  • 抱歉这里的延迟 - 我已经添加了您建议的添加内容的编辑,但是正如解释的那样,它不太正确!
【解决方案2】:

您只是没有使用正确的查询。您的查询应该是:

if ($seasonId = $request->input('seasonId')) {
    $season = Season::findOrFail($seasonId);

    $divisionIdsQuery = $season->divisions()
        ->select('divisions.id')
        ->groupBy('divisions.id')
        ->getQuery(); // can't just ->get(), because MYSQL FULL GROUP BY.

    $divisions = Division::whereIn('id', $divisionIdsQuery)
        ->with(['teams' => function ($query) use ($season) {
            $query->where('season_id', $season->id);
        }])
        ->get();

    return $this->respond(new DivisionCollection($divisions));
}

【讨论】:

  • 您好,这很接近,尽管对于给定分区中的每个团队,它都会返回分区和团队的次数。例如,池 A 有 5 个团队,您的代码返回池 A 和正确的团队,但它会这样做 5 次
  • @DJC 对不起,我不明白你想要什么。您能否编辑您的问题并向我们提供您想要的示例结果?
  • 抱歉,我没有收到 pool_a 和那个赛季的球队(这是我想要的),而是收到相同的结果重复 x 次 - x 是那个赛季的球队数量那个赛季的分区。这是有道理的,因为对于 Division_season_team 中的每个团队,都会插入一个包含 Division_id 的新行,因此我会为每一行获取分区及其团队。
  • 哦,好的,我明白了。让我试试。
【解决方案3】:

阅读您的编辑后,我认为您可以通过加入团队with 来获得此信息。

表格:

seasons
divisions
teams
season_divisions_teams
  - season_id
  - division_id
  - team_id 

在您的控制器中:

if ($request->query('seasonId')) {
    $seasonId = $request->query('seasonId');

    $result = Division::with(['teams' => function (Builder $query) use ($seasonId) {
        $query->select(["teams.*"]);
        $query->join('season_divisions_teams', 'season_divisions_teams.team_id', '=', 'teams.id');
        $query->where('season_divisions_teams.season_id', '=', $seasonId);
    }])
    ->whereHas('seasons', function(Builder $query) use ($seasonId) {
        $query->where('season_id', '=', $seasonId);
    })->get();

    return $this->respond(new DivisionCollection($result));
}

解释:

就像我们调用with('teams') 时调用divisionsteams 之间的关系一样,不属于该分区的团队将被排除在外。之后,我们使用 teamsseason_divisions_teams 之间的连接来获取有关赛季中球队的信息,并使用 where 按赛季 ID 过滤它们。

【讨论】:

  • 您好,谢谢您 - 虽然我收到错误 - 语法错误或访问冲突:1066 不是唯一的表/别名:'season_divisions_teams'
猜你喜欢
  • 2021-12-15
  • 1970-01-01
  • 2016-03-18
  • 1970-01-01
  • 1970-01-01
  • 2019-05-10
相关资源
最近更新 更多