2013-03-26 13 views
13

Próbowałem zdefiniować jakiś schemat bazy danych, aby użyć frameworka laravel. Chcę modelować mecz piłki nożnej. Pierwszym krokiem, jaki chciałem zrobić, było zdefiniowanie diagramu relacji encji, ale znalazłem to (co uważałem za dość trywialne), aby było mylące w niektórych aspektach.Baza danych One-to-Many z dwoma kluczami obcymi w Laravel

Po pierwsze, oczywistym podejściem jest stwierdzenie, że mecz jest powiązany z dwoma drużynami, a drużyna jest powiązana z dowolną liczbą meczów. Tak więc chcielibyśmy mieć relację "wiele do wielu".

Ale implementacja relacji wiele do wielu polega na tym, że dwie tabele i tabela pośrednia odnoszą się do obu podmiotów. Myślę, że byłoby to zbyt wiele, gdy wiem, że mecz zawsze będzie miał dwa zespoły i wystarczy mieć dwie kolumny (local_id i visitant_id) z obcymi kluczami do tabeli drużyn. Plus, chcę być w stanie to zrobić:

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

więc, myśląc o tym jestem wdrożenie „jeden do wielu” relacji, ale z tym mam inny problem. Aby pobrać wszystkie mecze zespół grał chciałbym zrobić:

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

Ale nie mogę tego zrobić, ponieważ można określić tylko jedną kolumnę klucza przy określaniu mecze() metoda w wymowny (domyślnie byłoby team_id, ale powinno to być visant_id i local_id).

Odpowiedz

31

Po jakimś bardziej kopanie w kodzie źródłowym znalazłem istnieje sposób, aby rzeczywiście utrzymać moje schematu bazy danych, jak to jest i osiągnąć to, co chcę (przynajmniej w laravel 4) . I pisał mój problem w github i Taylor Otwell (twórca ram) dał mi poprawną odpowiedź: https://github.com/laravel/framework/issues/1272

Cytując go, powinno być tak proste, jak to:

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

a potem ...

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

Aktualizacja: Link GitHub nie działa, ponieważ nie bierze laravel raporty o błędach w ten sposób więcej: http://laravel-news.com/2014/09/laravel-removes-github-issues/

+0

dla mnie to powraca tylko modele powiązane z "visitant_id" ... – ciccioassenza

+0

To nadal działa w Laravel 5.2 – arleslie

+0

W Laravel 5.3 $ jest to pusty obiekt modelu. Jakieś pomysły, jak to osiągnąć w Laravel 5.3? –

3

Jest to jeden z tych słynnych problemów z projektowaniem baz danych. Związki przyjaźni na przykład cierpią z powodu tej samej trudności. Ponieważ używasz wymowny, chciałbym zaproponować, aby trzymać się z wielu do wielu podejścia i mają dodatkowy logiczną kolumny local na pośredniej tabeli

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

Obs:

Sposób has_many_and_belongs_to(...)->with('field') ma nic wspólnego z niecierpliwością na ładowanie. Informuje on firmę Eloquent, aby wczytała kolumnę stołu pośredniego field i umieściła ją w osi przegubu.

Zastosowanie:

$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 
    } 
} 
Powiązane problemy