2013-03-26 3 views
13

Я пытаюсь определить некоторую схему базы данных для использования рамки laravel. Я хочу смоделировать футбольный матч. Первый шаг, который я хотел сделать, - это определить диаграмму Entity Relationship, но я нашел это (что, по моему мнению, было бы довольно тривиальным) в некоторых аспектах сбивать с толку.База данных «Один-ко-многим» с двумя полями внешнего ключа в Laravel

Во-первых, очевидный подход состоит в том, чтобы сказать, что Матч связан с двумя командами, а команда связана с любым количеством совпадений. Итак, у нас было бы отношение «от многих до многих».

Но реализация отношения многих-многих состоит в том, чтобы иметь две таблицы и промежуточную таблицу для связывания обоих объектов. Я думаю, что это будет слишком много, когда я знаю, что в матче всегда будет две Команды, и просто иметь два столбца (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; 

Update: ссылка GitHub не работает, потому что Laravel не принимает сообщения об ошибках в том, как больше: http://laravel-news.com/2014/09/laravel-removes-github-issues/

+0

для меня это возвращает только «visitant_id» связанные модели ... – ciccioassenza

+0

Это все еще работает в Laravel 5.2 – arleslie

+0

В Laravel 5.3 $ это пустой объект модели. Любые идеи, как достичь этого в Laravel 5.3? –

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 
    } 
}