2013-03-26 172 views
13

我一直在試圖定義一些數據庫模式來使用laravel框架。我想模擬一場足球比賽。我想要做的第一步是定義實體關係圖,但是我發現這一點(我認爲這很不重要)會在某些方面造成混淆。在Laravel中有兩個外鍵字段的數據庫一對多

首先,顯而易見的方法是說Match與兩個團隊有關,而一個團隊與任意數量的Matches相關。所以,我們會有一個「多對多」的關係。

但是,多對多關係的實現是有兩個表和一箇中間表來關聯兩個實體。我認爲這太過分了,當我知道一場比賽總是有兩個球隊,並且只有兩個球隊(local_id和visitant_id)與球隊表中的外鍵足夠。另外,我希望能夠做到:

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

所以,在思考這個我實現了「一對多」的關係,但與此我有另外一個問題。要檢索一個團隊發揮了所有的比賽,我想這樣做:

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

但我不能這樣做,因爲定義在雄辯的比賽()方法時(默認情況下它會是我只能指定一個鍵列team_id,但它應該是visitant_id和local_id)。

回答

31

經過一些挖掘到的源代碼,我發現那裏是真正讓我的數據庫模式,因爲它是和達到我想要的方式(至少在Laravel 4) 。我張貼了我的問題,在github上和泰勒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; 

更新: GitHub的鏈接不工作,因爲laravel不採取這種方式更多的bug報告:http://laravel-news.com/2014/09/laravel-removes-github-issues/

+0

對我來說這個回報只是「visitant_id」的相關模型而已...... – ciccioassenza 2015-08-23 00:05:48

+0

這仍然適用於Laravel 5.2 – arleslie 2016-09-02 05:23:02

+0

在Laravel 5.3 $這是一個空的模型對象。任何想法如何在Laravel 5.3中實現? – 2017-03-03 09:42:37

3

這是那些着名的數據庫設計問題之一。例如,友誼關係也會遇到同樣的困難。由於使用的是口才好,我建議你多堅持了許多方法,並有一個額外的布爾列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 
    } 
} 
相關問題