2013-03-26 12 views
13

Ho cercato di definire alcuni schemi del database per utilizzare il framework laravel. Voglio modellare una partita di calcio. Il primo passo che ho voluto fare è definire il diagramma di Entity Relationship, ma ho trovato questo (che pensavo sarebbe stato piuttosto banale) essere confuso in alcuni aspetti.Database uno-a-molti con due campi chiave esterna in Laravel

In primo luogo, l'approccio ovvio è quello di dire che una partita è legata a due squadre, e una squadra è legata a qualsiasi numero di partite. Quindi, avremmo una relazione "Molti a molti".

Ma l'implementazione di una relazione molti-molti è di avere due tabelle e una tabella intermedia per collegare entrambe le entità. Penso che sarebbe troppo, quando so che una partita avrà sempre due squadre e semplicemente due colonne (local_id e visitant_id) con chiavi esterne alla tabella dei team sarebbe sufficiente. Inoltre, voglio essere in grado di fare:

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

Così, pensando a questo sono l'attuazione di un "uno a molti" relazione, ma con questo non ho un altro problema. Per recuperare tutte le partite di una squadra ha giocato vorrei fare:

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

Ma non posso fare questo perché posso specificare una sola colonna chiave nella definizione delle partite() metodo in eloquenti (per impostazione predefinita, sarebbe team_id, ma dovrebbe essere visitant_id e local_id).

risposta

31

Dopo un po 'di più a scavare nel codice sorgente che ho trovato non v'è un modo per mantenere in realtà la mia schema del database in quanto è e raggiungere ciò che voglio (almeno in laravel 4) . Ho inviato il mio problema in github e Taylor Otwell (creatore del quadro) mi ha dato la risposta corretta: https://github.com/laravel/framework/issues/1272

citarlo, dovrebbe essere facile come questo:

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

E poi ...

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

Update: Il collegamento github non funziona perché laravel non prende segnalazioni di bug in questo modo più: http://laravel-news.com/2014/09/laravel-removes-github-issues/

+0

per me questo ritorno solo modelli "visitant_id" ... – ciccioassenza

+0

Questo funziona ancora in Laravel 5.2 – arleslie

+0

In Laravel 5.3 $ questo è un oggetto modello vuoto. Qualche idea su come ottenere ciò in Laravel 5.3? –

3

Questo è uno di quei famosi problemi di progettazione del database. Le relazioni di amicizia, ad esempio, soffrono della stessa difficoltà. Dal momento che si sta utilizzando Eloquente, vorrei suggerire di attaccare con molti a molti approccio e hanno una colonna aggiuntiva booleana local sulla vostra tabella intermedia

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:

Il metodo has_many_and_belongs_to(...)->with('field') non ha nulla a che fare con caricamento avido. Indica a Eloquent di caricare la colonna della tabella intermedia field e inserirla nel pivot.

Usage:

$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 
    } 
} 
Problemi correlati