Zwei meiner Tabellen (Kunden und Produkte) haben eine ManyToMany-Beziehung mit Laravels blongToMany und einer Pivot-Tabelle. Jetzt möchte ich überprüfen, ob ein bestimmter Kunde ein bestimmtes Produkt hat.
Ich könnte ein Modell zum Einchecken in die Pivot-Tabelle erstellen, aber da Laravel dieses Modell für die Methode "Gehört zu ToMany" nicht benötigt, habe ich mich gefragt, ob es eine andere Möglichkeit gibt, zu überprüfen, ob eine bestimmte Beziehung besteht, ohne ein Modell für die Pivot-Tabelle zu haben.
$exists = $client->products()->contains($product_id);
) tun, wird tatsächlich angegeben, dasscontains
dies am nicht vorhanden istBelongsToMany
. Wenn Sie es jedoch als Attribut aufrufen, wird BelongsToMany stillschweigend in eine Sammlung konvertiert, die dies hatcontains()
.Die Frage ist ziemlich alt, aber dies kann anderen helfen, nach einer Lösung zu suchen:
$client = Client::find(1); $exists = $client->products()->where('products.id', $productId)->exists();
Keine "Verschwendung" wie in der Lösung von @ alexrussell und die Abfrage ist auch effizienter.
quelle
SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias:
wenn ich das in meinem Modell versuche: /where('products.id', $productId)
.client
auch eine ID hat. Das ist ziemlich häufig.Alex 'Lösung funktioniert, aber sie lädt ein
Client
Modell und alle damit verbundenenProduct
Modelle aus der Datenbank in den Speicher und prüft erst danach, ob die Beziehung besteht.Ein besserer eloquenter Weg, dies zu tun, ist die Verwendung einer
whereHas()
Methode.1. Sie müssen das Client-Modell nicht laden, sondern können nur seine ID verwenden.
2. Sie müssen auch nicht alle mit diesem Client verbundenen Produkte in den Speicher laden, wie dies bei Alex der Fall ist.
3. Eine SQL-Abfrage an DB.
$doesClientHaveProduct = Product::where('id', $productId) ->whereHas('clients', function($q) use($clientId) { $q->where('id', $clientId); }) ->count();
quelle
Update: Ich habe die Nützlichkeit der Überprüfung mehrerer Beziehungen nicht berücksichtigt. Wenn dies der Fall ist, hat @deczo eine bessere Antwort auf diese Frage. Es ist die gewünschte Lösung, nur eine Abfrage auszuführen, um alle Beziehungen zu überprüfen.
/** * Determine if a Client has a specific Product * @param $clientId * @param $productId * @return bool */ public function clientHasProduct($clientId, $productId) { return ! is_null( DB::table('client_product') ->where('client_id', $clientId) ->where('product_id', $productId) ->first() ); }
Sie können dies in Ihr Benutzer- / Client-Modell einfügen oder in einem Client-Repository speichern und dort verwenden, wo Sie es benötigen.
if ($this->clientRepository->clientHasProduct($clientId, $productId) { return 'Awesome'; }
Wenn Sie die Zugehörigkeit zu ToMany bereits in einem Client Eloquent-Modell definiert haben, können Sie dies stattdessen in Ihrem Client-Modell tun:
return ! is_null( $this->products() ->where('product_id', $productId) ->first() );
quelle
Die Methoden von @ nielsiano werden funktionieren, aber sie werden die Datenbank für jedes Benutzer / Produkt-Paar abfragen, was meiner Meinung nach eine Verschwendung ist.
Wenn Sie nicht alle Daten der zugehörigen Modelle laden möchten, würde ich Folgendes für einen einzelnen Benutzer tun :
// User model protected $productIds = null; public function getProductsIdsAttribute() { if (is_null($this->productsIds) $this->loadProductsIds(); return $this->productsIds; } public function loadProductsIds() { $this->productsIds = DB::table($this->products()->getTable()) ->where($this->products()->getForeignKey(), $this->getKey()) ->lists($this->products()->getOtherKey()); return $this; } public function hasProduct($id) { return in_array($id, $this->productsIds); }
Dann können Sie einfach Folgendes tun:
$user = User::first(); $user->hasProduct($someId); // true / false // or Auth::user()->hasProduct($someId);
Es wird nur 1 Abfrage ausgeführt, dann arbeiten Sie mit dem Array.
Der einfachste Weg wäre die Verwendung von
contains
@alexrussell.Ich denke, dies ist eine Frage der Präferenz. Wenn Ihre App nicht sehr groß ist und viel Optimierung erfordert, können Sie auswählen, mit was Sie leichter arbeiten können.
quelle
col_id
und welche qualifiziert / vorangestellt sindtable.col_id
. Leider fehlt Eloquent ziemlich oft die Konsistenz.Hallo an alle) Meine Lösung für dieses Problem: Ich habe eine eigene Klasse erstellt, die von Eloquent erweitert wurde, und alle meine Modelle daraus erweitert. In dieser Klasse habe ich diese einfache Funktion geschrieben:
function have($relation_name, $id) { return (bool) $this->$relation_name()->where('id','=',$id)->count(); }
Um eine bestehende Beziehung zu überprüfen, müssen Sie Folgendes schreiben:
if ($user->have('subscribes', 15)) { // do some things }
Auf diese Weise wird nur eine SELECT-Zählabfrage (...) generiert, ohne dass echte Daten aus Tabellen empfangen werden.
quelle
Verwenden Sie das Merkmal:
trait hasPivotTrait { public function hasPivot($relation, $model) { return (bool) $this->{$relation}()->wherePivot($model->getForeignKey(), $model->{$model->getKeyName()})->count(); } }
.
if ($user->hasPivot('tags', $tag)){ // do some things... }
quelle
Um das Vorhandensein einer Beziehung zwischen zwei Modellen zu überprüfen, benötigen wir lediglich eine einzelne Abfrage für die Pivot-Tabelle ohne Verknüpfungen.
Sie können dies mit der integrierten
newPivotStatementForId
Methode erreichen:quelle
Das hat Zeit, aber vielleicht kann ich jemandem helfen
if($client->products()->find($product->id)){ exists!! }
Es sollte beachtet werden, dass Sie das Produkt- und Kundenmodell haben müssen, ich hoffe es hilft,
quelle