2017-11-18 4 views
0

Ich habe zwei Tabellen, Sendungen und Kunden. In der realen Welt kann ein Kunde auf drei Arten mit einer Lieferung in Verbindung gebracht werden: als Rechnungssteller, Zielort und/oder Herkunft.Drei-Wege-Pivot-Tabelle oder komplexe Beziehung in Laravel

Also meine Frage hier ist, habe ich eine Pivot-Tabelle mit drei Spalten, eine für die shipment_id, eine für die customer_id und eine für die Beziehungstyp-ID? Oder habe ich separate Tabellen? Ich bin mir nicht sicher, wie ich das am besten angehen könnte, da es die erste dieser Art ist, gegen die ich ankämpfe.

+0

kann sich ein Kunde in Ihre App einloggen? – lewis4u

+0

@ lewis4u, ja das ist einer der letzten beabsichtigten Zwecke. – Matthew

+0

Nun, das ist dein erster Fehler ... jeder, der sich in deine App einloggen kann, sollte in der Benutzertabelle sein. und dann erstellen Sie die Rollentabellen und weisen den Benutzern Rollen zu, das ist die beste Vorgehensweise. Ein Benutzer kann viele Sendungen haben, und jede Sendung gehört nur einem Benutzer. Das sollte deine erste Beziehung sein. Eine andere Beziehung ist offensichtlich: Ein Benutzer kann viele Rollen haben und jede Rolle gehört vielen Benutzern. Dieser würde mit einem Pivot-Tisch gemacht werden. – lewis4u

Antwort

1

Ich habe dieses Paar vor Wochen konfrontiert und ich kam mit einer Lösung.

Angenommen, dass ein Kunde verschiedene Relationen zu verschiedenen Sendungen haben kann.

Zunächst einmal brauchen Sie ein neues Modell für Kundenrollen, das Modell wird natürlich Relation-Modell sein.

Erster Ansatz: Sie könnten dies lösen, indem Sie mehr als eine Pivot-Tabelle verwenden, die funktioniert, aber es ist kein gutes Datenbank-Design. Ich habe es zuerst so gelöst, habe aber festgestellt, dass es nicht optimal ist, wenn es um db geht.

Zweiter Ansatz: Sie könnten dies lösen, indem Sie Pivot-Tabelle als Modell definieren, aber ich habe es nicht versucht, obwohl ich weiß, dass es funktioniert und es eine Lösung ist.

Besserer Ansatz: Verwenden Sie eine Pivot-Tabelle für drei Modelle. In diesem Fall müssen Sie Pivot-Tabelle definieren, wenn Sie eine Beziehung definieren Beispiel:

Kundenmodell:

public function relations() 
{ 
    return $this->belongsToMany(Relation::class, 'customer_relation_shippment'); 
} 

Relation Modell:

public function customers() 
{ 
    return $this->belongsToMany(Relation::class, 'customer_relation_shippment'); 
} 

und das andere Modell auch.

Jetzt sagen wir, Sie möchten eine Beziehung zu einem Kunden hinzufügen. Lets ersten Kunden und erste Lieferung packen und sagen, dass wir eine Beziehung als Rechnungssteller hinzufügen möchten:

$customer = Customer::first(); 

$shipment = Shipment::first(); 

$relation = Relation::where('name','biller')->get(); 

$customer->relations()->attach($shipment->id, ['relationship_type'=>$relation->id]); 

Mit nur einer Pivot-Tabelle natürlich ist es ein wenig komplizierter mit Operationen auf diesen Modellen wie CRUD ausführen, aber Wenn es um Datenbankdesign/Optimierung geht, ist es natürlich die richtige Wahl! Beachten Sie, dass ich zu dieser Schlussfolgerung gekommen bin, nachdem ich mich mit einem ähnlichen Problem in der realen Welt befasst habe und dass es viel schnellere Db-Interaktion mit mehr als einem Pivot verwendet hat.

+0

können sich Ihre Kunden mit Benutzername und Passwort in Ihre App einloggen? – lewis4u

+0

Mein Fall ist etwas weiter fortgeschritten als das, aber ja, ich habe einen Master-Admin, der Benutzerrollen definiert und zufällige Benutzer, die von Master-Admin definiert sind, können sie anmelden und überprüfen Sie ihre Sendung Fortschritt. –

+0

Ich habe nur das Gefühl, dass das OP die Dinge verkompliziert. Die bekannte Best Practice ist, dass jeder, der sich anmelden kann, automatisch ein Benutzer ist und in die Benutzertabelle gehört, und dieser Benutzer kann dann einige Rollen haben. Ein Kunde, Käufer, Verkäufer, Administrator, Manager oder jeder andere ... und dann kann dieser Benutzer Sendungen oder was auch immer haben. Es gibt keine Notwendigkeit für Kundenmodell und Beziehungsmodell ... das bricht die Regeln .... Ein Kunde ist ein Benutzer der App und Beziehung besteht zwischen Modellen und es wird zwischen ihnen erklärt – lewis4u

0

So würde ich Ihr Projekt gestalten.

Ich glaube nicht, dass Sie sogar eine Pivot-Tabelle oder viele-zu-viele-Beziehung benötigen.

Hinweis: Aus Gründen der Klarheit und die Vermeidung von Verwechslungen mit den User, werde ich Account verwenden, um zu verweisen, was man ein Customer nennen. Am Ende haben Sie customer account in Ihren Kommentaren verwendet.

Sie haben eine Lieferung, die sich auf drei verschiedene Einheiten bezieht.Diese Entitäten werden jedoch durch dasselbe Datenmodell in Ihrer Datenbank repräsentiert: das Account Modell.

Eine einfache Eins-zu-viele-Beziehung reicht aus.

Ein Konto kann viele Sendungen haben. Und die Sendung gehört ein Konto.

Jetzt, wie man den "Typ" der Beziehung hinzufügt? Wir brauchen keine Pivot-Tabelle, sondern fügen einfach eine weitere Eins-zu-Viele-Beziehung hinzu.

  • Ein Account as biller können viele Sendungen haben, und die Sendung gehört zu einem biller.

  • Ein Account as origin kann viele Sendungen haben, und die Sendung gehört zu einem origin.

  • Ein Account as destination kann viele Sendungen haben, und die Sendung gehört zu einem origin.

, hier zu erklären, ist ein Beispielcode:

Wir haben drei Modelle: User, Account und Shipment

die mit dem Schema Beginnen wir:

Schema::create('accounts', function (Blueprint $table) { 
     $table->increments('id'); 
     $table->string('name'); 
     $table->timestamps(); 
    }); 

    Schema::create('shipments', function (Blueprint $table) { 
     $table->increments('id'); 
     $table->string('from'); 
     $table->string('to'); 

     $table->unsignedInteger('biller_id'); 
     $table->unsignedInteger('origin_id'); 
     $table->unsignedInteger('destination_id'); 

     $table->foreign('biller_id') 
      ->references('id')->on('accounts'); 

     $table->foreign('origin_id') 
      ->references('id')->on('accounts'); 

     $table->foreign('destination_id') 
      ->references('id')->on('accounts'); 

     $table->timestamps(); 
    }); 

Wir haben drei Spalten, die auf die id auf derverweisenTabelle.

Für die Modelle und die Beziehungen:

Konto Modell:

class Account extends Model 
{ 
    public function billerShipments() 
    { 
     return $this->hasMany(Shipment::class, 'biller_id'); 
    } 

    public function originShipments() 
    { 
     return $this->hasMany(Shipment::class, 'origin_id'); 
    } 

    public function destinationShipments() 
    { 
     return $this->hasMany(Shipment::class, 'destination_id'); 
    } 

    public function users() 
    { 
     return $this->belongsToMany(User::class); 
    } 

} 

Versand Modell:

class Shipment extends Model 
{ 
    public function billerAccount() 
    { 
     return $this->belongsTo(Account::class, 'biller_id'); 
    } 

    public function originAccount() 
    { 
     return $this->belongsTo(Account::class, 'origin_id'); 
    } 

    public function destinationAccount() 
    { 
     return $this->belongsTo(Account::class, 'destination_id'); 
    } 

} 

Beispiel eine Sendung

zu erstellen
$billerAccount = \App\Account::create(['name' => 'account b']); 
    $originAccount = \App\Account::create(['name' => 'account a']); 
    $destinationAccount = \App\Account::create(['name' => 'account c']); 

    $newShipment = \App\Shipment::create([ 
     'from'   => 'city 1', 
     'to'    => 'city 2', 
     'biller_id'  => $billerAccount->id, 
     'origin_id'  => $originAccount->id, 
     'destination_id' => $destinationAccount->id, 
    ]); 

    echo $billerAccount->billerShipments()->count(); // 1 
    echo $originAccount->originShipments()->count(); // 1 
    echo $destinationAccount->destinationShipments()->count(); // 1 

    echo $newShipment->billerAccount->name === $billerAccount->name; // 1 
    echo $newShipment->originAccount->name === $originAccount->name; // 1 
    echo $newShipment->destinationAccount->name === $destinationAccount->name; // 1 

Für die Konto-Benutzer-Beziehungen kann es abhängig von Ihren Anforderungen viele-zu-viele oder eins-zu-viele sein.