> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Einführung in Eloquent-Relationen

> Erläutert, wie Sie mit Eloquent Beziehungen zwischen Tabellen (1:1, 1:n, n:m) definieren und die zugehörigen Daten effizient abrufen.

## Was ist eine Relation?

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.

<Info>
  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.
</Info>

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)                  |
| `belongsToMany` | n:m (nutzt eine Zwischentabelle)                                    |

```mermaid theme={null}
erDiagram
    users ||--o| profiles : "hasOne / belongsTo (profiles.user_id)"
    posts ||--o{ comments : "hasMany / belongsTo (comments.post_id)"
    posts }o--o{ tags : "belongsToMany (Zwischentabelle post_tag)"
```

## hasOne (1:1)

`hasOne` beschreibt, dass ein Modell genau eine Instanz eines anderen Modells besitzt. Zum Beispiel besitzt ein `User` genau ein `Profile`.

### Relation definieren

Fügen Sie im `User`-Modell eine Methode `profile` hinzu.

```php theme={null}
<?php

namespace 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.

### Verknüpfte Daten laden

Auf definierte Relationen greifen Sie wie auf Properties zu.

```php theme={null}
$user = User::find(1);
$profile = $user->profile;
```

<Tip>
  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".
</Tip>

## belongsTo (Umkehrung der 1:1-Relation)

`belongsTo` ist die Umkehrung von `hasOne` und wird auf der Seite mit dem Fremdschlüssel definiert. Es beschreibt, dass `Profile` zu einem `User` gehört.

### Relation definieren

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Profile extends Model
{
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }
}
```

Eloquent nutzt den Namen der Relationsmethode plus `_id` als Fremdschlüsselspalte – hier also `user_id`.

### Verknüpfte Daten laden

```php theme={null}
$profile = Profile::find(1);
$user = $profile->user;

echo $user->name;
```

## hasMany (1:n)

`hasMany` ist die am häufigsten genutzte Relation: Ein Elternmodell besitzt mehrere Kindmodelle. Zum Beispiel besitzt ein `Post` mehrere `Comment`s.

### Relation definieren

```php theme={null}
<?php

namespace 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.

### Verknüpfte Daten laden

Eine `hasMany`-Relation liefert eine Collection zurück.

```php theme={null}
$post = Post::find(1);

foreach ($post->comments as $comment) {
    echo $comment->body;
}
```

Sie können zusätzliche Bedingungen anhängen.

```php theme={null}
$recentComments = Post::find(1)
    ->comments()
    ->latest()
    ->take(5)
    ->get();
```

### Umkehrung (belongsTo)

Um vom Kommentar zum Beitrag zu navigieren, definieren Sie im `Comment`-Modell `belongsTo`.

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Comment extends Model
{
    public function post(): BelongsTo
    {
        return $this->belongsTo(Post::class);
    }
}
```

```php theme={null}
$comment = Comment::find(1);
echo $comment->post->title;
```

## belongsToMany (n:m)

Eine n:m-Relation nutzen Sie, wenn beide Modelle jeweils mehrere Verknüpfungen haben können. Zum Beispiel: Ein `Post` gehört zu mehreren `Tag`s, und ein `Tag` gehört zu mehreren `Post`s.

### Tabellenaufbau

Für eine n:m-Relation benötigen Sie eine Zwischentabelle. Für `Post` und `Tag` legen wir dazu `post_tag` an.

```text theme={null}
posts
    id - integer
    title - string

tags
    id - integer
    name - string

post_tag
    post_id - integer
    tag_id - integer
```

<Info>
  Den Namen der Zwischentabelle leitet Eloquent automatisch ab, indem die beiden Modellnamen alphabetisch verkettet werden (`post` + `tag` → `post_tag`).
</Info>

### Relation definieren

```php theme={null}
<?php

namespace 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.

```php theme={null}
<?php

namespace 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);
    }
}
```

### Verknüpfte Daten laden

```php theme={null}
$post = Post::find(1);

foreach ($post->tags as $tag) {
    echo $tag->name;
}
```

### Verknüpfte Datensätze hinzufügen und entfernen

Mit `attach` fügen Sie Einträge in die Zwischentabelle ein, mit `detach` entfernen Sie sie.

```php theme={null}
$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]);
```

<Tip>
  Mit `sync` entfernt Eloquent alle Einträge der Zwischentabelle außer den angegebenen IDs, sodass nur die übergebenen IDs als Verknüpfungen bestehen bleiben.
</Tip>

## Eager Loading

### Was ist das N+1-Problem?

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.

```php theme={null}
// 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.

### Eager Loading mit with()

Mit der Methode `with()` laden Sie verknüpfte Daten in einem Rutsch, sodass insgesamt nur zwei Queries nötig sind.

```php theme={null}
// 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:

```sql theme={null}
select * from posts

select * from users where id in (1, 2, 3, ...)
```

### Mehrere Relationen gleichzeitig Eager laden

Mit einem Array können Sie mehrere Relationen angeben.

```php theme={null}
$posts = Post::with(['user', 'comments', 'tags'])->get();
```

### Verschachteltes Eager Loading

Mit Punkt-Notation können auch verschachtelte Relationen Eager geladen werden.

```php theme={null}
// Kommentare zu Beiträgen und deren Nutzer Eager laden
$posts = Post::with('comments.user')->get();
```

<Warning>
  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.
</Warning>

## Nächste Schritte

<Card title="Einführung in Eloquent" icon="database" href="/de/eloquent">
  Wiederholen Sie die grundlegenden CRUD-Operationen von Eloquent.
</Card>


## Related topics

- [Einführung in Eloquent](/de/eloquent.md)
- [Eloquent-API-Ressourcen](/de/eloquent-resources.md)
- [Eloquent-Serialisierung](/de/eloquent-serialization.md)
- [Eloquent-Factories](/de/eloquent-factories.md)
- [Eloquent-Collections](/de/eloquent-collections.md)
