Datenbanktabellen stehen häufig in Beziehung zueinander. So kann ein Blog-Beitrag viele Kommentare haben oder eine Bestellung mit dem Nutzer verknüpft sein, der sie aufgegeben hat.Eloquent stellt einen einfachen Mechanismus bereit, um solche Beziehungen (Relationen) zu definieren und mit ihnen zu arbeiten. Relationen werden als Methoden im Eloquent-Modell definiert.
Auf dieser Seite dienen konkrete Modelle wie User, Post, Comment und Tag als Beispiele.
Wir gehen davon aus, dass die Modelle und Tabellen bereits vorhanden sind.
Eloquent unterstützt insbesondere folgende Relationen:
Relation
Beschreibung
hasOne
1:1 (das Elternmodell besitzt ein Kindmodell)
belongsTo
Umkehrung der 1:1-Relation (das Kindmodell gehört zum Elternmodell)
hasMany
1:n (ein Elternmodell besitzt mehrere Kindmodelle)
Fügen Sie im User-Modell eine Methode profile hinzu.
<?phpnamespace App\Models;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\HasOne;class User extends Model{ public function profile(): HasOne { return $this->hasOne(Profile::class); }}
Eloquent leitet den Fremdschlüssel automatisch aus dem Elternmodellnamen ab. Hier wird also erwartet, dass die Tabelle profiles eine Spalte user_id besitzt.
Auf definierte Relationen greifen Sie wie auf Properties zu.
$user = User::find(1);$profile = $user->profile;
Wird eine Relation-Methode als Property aufgerufen, führt Eloquent automatisch eine Query aus und liefert die verknüpften Daten. Man spricht von „Dynamic Relationship Properties”.
<?phpnamespace App\Models;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\HasMany;class Post extends Model{ public function comments(): HasMany { return $this->hasMany(Comment::class); }}
Eloquent erwartet, dass die Tabelle comments eine Spalte post_id besitzt.
Eine n:m-Relation nutzen Sie, wenn beide Modelle jeweils mehrere Verknüpfungen haben können. Zum Beispiel: Ein Post gehört zu mehreren Tags, und ein Tag gehört zu mehreren Posts.
<?phpnamespace App\Models;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\BelongsToMany;class Post extends Model{ public function tags(): BelongsToMany { return $this->belongsToMany(Tag::class); }}
Analog definieren Sie die Relation auf der Tag-Seite, um sie in beide Richtungen abfragen zu können.
<?phpnamespace App\Models;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\BelongsToMany;class Tag extends Model{ public function posts(): BelongsToMany { return $this->belongsToMany(Post::class); }}
Mit attach fügen Sie Einträge in die Zwischentabelle ein, mit detach entfernen Sie sie.
$post = Post::find(1);// Tag hinzufügen$post->tags()->attach($tagId);// Tag entfernen$post->tags()->detach($tagId);// Alle bestehenden Verknüpfungen ersetzen$post->tags()->sync([$tagId1, $tagId2]);
Mit sync entfernt Eloquent alle Einträge der Zwischentabelle außer den angegebenen IDs, sodass nur die übergebenen IDs als Verknüpfungen bestehen bleiben.
Wenn Sie Relationen als Property abrufen, führt Eloquent bei jedem Zugriff eine eigene Query aus. Das nennt sich „Lazy Loading”. Greifen Sie in einer Schleife auf Relationen zu, entsteht das N+1-Problem.
// Eine Query zum Laden aller Beiträge$posts = Post::all();foreach ($posts as $post) { // Für jeden Beitrag wird eine eigene Query für den User ausgeführt (N-mal) echo $post->user->name;}
Bei 100 Beiträgen werden insgesamt 101 Queries ausgeführt – ein erheblicher Performance-Nachteil.
Mit der Methode with() laden Sie verknüpfte Daten in einem Rutsch, sodass insgesamt nur zwei Queries nötig sind.
// Beiträge und ihre User in zwei Queries laden$posts = Post::with('user')->get();foreach ($posts as $post) { // Keine zusätzlichen Queries mehr echo $post->user->name;}
Ausgeführt werden nur die folgenden zwei SQL-Statements:
select * from postsselect * from users where id in (1, 2, 3, ...)
Mit Punkt-Notation können auch verschachtelte Relationen Eager geladen werden.
// Kommentare zu Beiträgen und deren Nutzer Eager laden$posts = Post::with('comments.user')->get();
Eager Loading ist entscheidend, um das N+1-Problem zu vermeiden. Machen Sie es sich zur Gewohnheit, in Schleifen immer with() zu verwenden, wenn Sie auf Relationen zugreifen.