Laravel war auf Beziehungsobjekt


74

Ich entwickle eine Web-API mit Laravel 5.0, bin mir jedoch nicht sicher, welche Abfrage ich erstellen möchte.

Meine Klassen sind wie folgt:

class Event extends Model {

    protected $table = 'events';
    public $timestamps = false;

    public function participants()
    {
        return $this->hasMany('App\Participant', 'IDEvent', 'ID');
    }

    public function owner()
    {
        return $this->hasOne('App\User', 'ID', 'IDOwner');
    }
}

und

class Participant extends Model {

    protected $table = 'participants';
    public $timestamps = false;

    public function user()
    {
        return $this->belongTo('App\User', 'IDUser', 'ID');
    }

    public function event()
    {
        return $this->belongTo('App\Event', 'IDEvent', 'ID');
    }
}

Jetzt möchte ich alle Veranstaltungen mit einem bestimmten Teilnehmer erhalten. Ich habe versucht mit:

Event::with('participants')->where('IDUser', 1)->get();

aber die whereBedingung wird auf die Eventund nicht auf ihre angewendet Participants. Folgendes gibt mir eine Ausnahme:

Participant::where('IDUser', 1)->event()->get();

Ich weiß, dass ich das schreiben kann:

$list = Participant::where('IDUser', 1)->get();
for($item in $list) {
   $event = $item->event;
   // ... other code ...
}

Es scheint jedoch nicht sehr effizient zu sein, so viele Anfragen an den Server zu senden.

Was ist der beste Weg, um wheremit Laravel 5 und Eloquent eine Modellbeziehung durchzuführen ?


2
Was war die Ausnahme?
Danny Kopping

Antworten:


185

Die richtige Syntax für Ihre Beziehungen lautet:

Event::whereHas('participants', function ($query) {
    return $query->where('IDUser', '=', 1);
})->get();

Lesen Sie mehr unter https://laravel.com/docs/5.8/eloquent-relationships#eager-loading


15
Zum besseren Verständnis: Dies gibt Ereignisse zurück, bei denen die Teilnehmer eine Benutzer-ID von 1 haben. Wenn der Teilnehmer keine Benutzer-ID von 1 hat, wird das Ereignis NICHT zurückgegeben.
Chuck Le Butt

62

Die Antwort von @ Cermbo bezieht sich nicht auf diese Frage. In ihrer Antwort wird Laravel Sie alle geben , Eventswenn jeder Eventhat 'participants'mit IdUserder 1.

Aber wenn Sie alles Eventsmit allem bekommen wollen, 'participants'vorausgesetzt, alle 'participants'haben eine IdUser1, dann sollten Sie so etwas tun:

Event::with(["participants" => function($q){
    $q->where('participants.IdUser', '=', 1);
}])

NB:

in whereGebrauch Ihre Tabellennamen, nicht Modellname.


15
Zum besseren Verständnis: Im Gegensatz zur anderen Antwort werden ALLE Ereignisse zurückgegeben, unabhängig davon, ob der Teilnehmer eine Benutzer-ID von 1 hat oder nicht. Das Teilnehmerobjekt wird jedoch nur dann eingeschlossen, wenn dies der Fall ist.
Chuck Le Butt

6

Verwenden Sie bei mehreren Verknüpfungen etwa den folgenden Code:

Event::with(["owner", "participants" => function($q) use($someId){
    $q->where('participants.IdUser', '=', 1);
    //$q->where('some other field', $someId);
}])

5
    return Deal::with(["redeem" => function($q){
        $q->where('user_id', '=', 1);
    }])->get();

das hat bei mir funktioniert


0

Ich habe in BaseModel einen benutzerdefinierten Abfragebereich erstellt (alle Modelle erweitern diese Klasse):

/**
 * Add a relationship exists condition (BelongsTo).
 *
 * @param  Builder        $query
 * @param  string|Model   $relation   Relation string name or you can try pass directly model and method will try guess relationship
 * @param  mixed          $modelOrKey
 * @return Builder|static
 */
public function scopeWhereHasRelated(Builder $query, $relation, $modelOrKey = null)
{
    if ($relation instanceof Model && $modelOrKey === null) {
        $modelOrKey = $relation;
        $relation   = Str::camel(class_basename($relation));
    }

    return $query->whereHas($relation, static function (Builder $query) use ($modelOrKey) {
        return $query->whereKey($modelOrKey instanceof Model ? $modelOrKey->getKey() : $modelOrKey);
    });
}

Sie können es in vielen Kontexten verwenden, zum Beispiel:

Event::whereHasRelated('participants', 1)->isNotEmpty(); // where has participant with id = 1 

Außerdem können Sie versuchen, den Beziehungsnamen wegzulassen und nur das Modell zu übergeben:

$participant = Participant::find(1);
Event::whereHasRelated($participant)->first(); // guess relationship based on class name and get id from model instance

0

[OOT]

Ein bisschen OOT, aber diese Frage ist das Thema, das meiner Frage am nächsten kommt.

Hier ist ein Beispiel, wenn Sie ein Ereignis anzeigen möchten, bei dem ALLE Teilnehmer bestimmte Anforderungen erfüllen. Angenommen, eine Veranstaltung, bei der ALLE Teilnehmer vollständig bezahlt haben . Es werden also KEINE Ereignisse zurückgegeben, bei denen ein oder mehrere Teilnehmer nicht vollständig bezahlt haben.

Verwenden Sie einfach den whereDoesntHaveStatus der anderen 2.

Nehmen wir an, die Status werden überhaupt nicht bezahlt [Gleichung: 1], haben einen Teil davon bezahlt [Gleichung: 2] und sind voll bezahlt [Gleichung: 3]

Event::whereDoesntHave('participants', function ($query) {
   return $query->whereRaw('payment = 1 or payment = 2');
})->get();

Getestet auf Laravel 5.8 - 7.x.


Die Dinge, die ich daran mag, sind, dass Sie immer noch das Beziehungsobjekt wieEvent::with(['participants, avenue])
Akbar Noto
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.