【问题标题】:Database One-to-Many with two foreign key fields in LaravelLaravel中具有两个外键字段的数据库一对多
【发布时间】:2013-03-16 19:34:26
【问题描述】:

我一直在尝试定义一些数据库模式来使用 laravel 框架。我想模拟一场足球比赛。我想做的第一步是定义实体关系图,但我发现这(我认为这很简单)在某些方面令人困惑。

首先,显而易见的方法是说一场比赛与两支球队相关,而一支球队与任意数量的比赛相关。所以,我们会有一个“多对多”的关系。

但是多对多关系的实现是有两个表和一个中间表来关联两个实体。我认为这太过分了,因为我知道一个 Match 总是有两个 Teams 并且只需有两列(local_id 和 visitant_id)以及 Teams 表的外键就足够了。另外,我希望能够做到:

Match::find(1)->local() or Match::find(1)->visitant();

因此,考虑到这一点,我正在实施“一对多”关系,但是对此我还有另一个问题。要检索团队参加过的所有比赛,我想做:

Team::find(1)->matches(); 

但我不能这样做,因为我在 eloquent 中定义 match() 方法时只能指定一个键列(默认为 team_id,但应该是 visitant_id 和 local_id)。

【问题讨论】:

    标签: database laravel eloquent


    【解决方案1】:

    在深入研究源代码后,我发现有一种方法可以实际保持我的数据库模式并实现我想要的(至少在 Laravel 4 中)。我在 github 上发布了我的问题,Taylor Otwell(框架的创建者)给了我正确的答案:https://github.com/laravel/framework/issues/1272

    引用他的话,应该就这么简单:

    class Team extends Eloquent  {
        public function allMatches()
        {
            return $this->hasMany('Match', 'visitant_id')->orWhere('local_id', $this->id);
        }
    }
    

    然后……

    $team = Team::find(2);
    $matches = $team->allMatches;
    

    【讨论】:

    • 在 Laravel 5.3 $this 是一个空模型对象。任何想法如何在 Laravel 5.3 中实现这一点?
    • 为什么这不能使用“with”方法作为“Team::with('allMatches')->find($id);”,它返回空数组,其中有 $team->allMatches效果好吗?
    • 当使用with 时,您会急切地加载关系。在急切加载时,$this 中的模型属性尚未水合,因此 $this->id 什么也不返回。
    【解决方案2】:

    这是著名的数据库设计问题之一。例如,友谊关系也面临同样的困难。由于您使用的是 Eloquent,我建议您坚持多对多方法,并在中间表上添加一个额外的布尔列 local

    class Match extends Eloquent {
        public $includes = array('team'); // Always eager load teams
        public function teams() {
            return $this->has_many_and_belongs_to('team')->with('local');
        }
        public function get_local() {
            foreach ($this->teams as $team) {
                if ($team->pivot->local) return $team;
            }
        }
        public function get_visitant()   {
            foreach ($this->teams as $team) {
                if (!$team->pivot->local) return $team;
            }
        }
    }
    
    class Team extends Eloquent  {
        public function matches() {
            return $this->has_many_and_belongs_to('match')->with('local');
        }
        // I'm doing separate queries here because a team may have
        // hundreds of matches and it's not worth looping through
        // all of them to retrieve the local ones
        public function matches_as_local()  {
            return $this->has_many_and_belongs_to('match')->with('local')
                ->where('pivot_local', '=', 1);
        }
        public function matches_as_visitant()  {
            return $this->has_many_and_belongs_to('match')->with('local')
                ->where('pivot_local', '=', 0);
        }
    }
    

    观察:

    has_many_and_belongs_to(...)->with('field') 方法与预加载无关。它告诉 Eloquent 加载中间表列 field 并将其放入数据透视表中。

    用法:

    $match = Match::find(1);
    
    $match->local; // returns local team
    $match->visitant; // returns visitant team
    
    $team = Team::find(1);
    $team->matches; // returns all matches
    $team->matches_as_local; // ...
    $team->matches_as_visitant; // ...
    
    foreach ($team->matches as $match) {
        if ($match->pivot->local) {
            // put nice local icon here
        } else {
            // put nice visitant icon here
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-23
      • 1970-01-01
      • 1970-01-01
      • 2020-10-04
      • 1970-01-01
      相关资源
      最近更新 更多