Vai al contenuto principale

Cosa sono le relazioni

Le tabelle di un database sono spesso correlate tra loro. Ad esempio, un post di blog ha molti commenti, oppure un ordine è collegato all’utente che l’ha effettuato. Eloquent offre un modo semplice per definire e manipolare queste relazioni tra tabelle. Le relazioni si definiscono come metodi sui modelli Eloquent.
In questa pagina usiamo come esempio modelli concreti come User, Post, Comment e Tag. Diamo per scontato che modelli e tabelle siano già stati creati.
Le principali relazioni supportate da Eloquent sono le seguenti.
RelazioneDescrizione
hasOne1-a-1 (il genitore ha un figlio)
belongsToInverso di 1-a-1 (il figlio appartiene al genitore)
hasMany1-a-molti (il genitore ha più figli)
belongsToManyMolti-a-molti (usa una tabella pivot)

hasOne (1-a-1)

hasOne rappresenta una relazione in cui un modello possiede esattamente un altro modello. Ad esempio, un User ha un Profile.

Definizione della relazione

Nel modello User definisci il metodo profile.
<?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 deduce automaticamente la chiave esterna dal nome del modello padre. Assume che la tabella profiles abbia una colonna user_id.

Recupero dei dati correlati

La relazione definita è accessibile come una proprietà.
$user = User::find(1);
$profile = $user->profile;
Chiamando il metodo di relazione come una proprietà, Eloquent emette automaticamente la query e restituisce i dati correlati. Questa è la “dynamic relationship property”.

belongsTo (inverso di 1-a-1)

belongsTo è l’inverso di hasOne e va definito sul modello che possiede la chiave esterna. Rappresenta la relazione “un Profile appartiene a un User”.

Definizione della relazione

<?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 usa come chiave esterna la colonna con nome-del-metodo + _id (in questo caso user_id).

Recupero dei dati correlati

$profile = Profile::find(1);
$user = $profile->user;

echo $user->name;

hasMany (1-a-molti)

hasMany è la relazione più usata: un modello padre possiede più figli. Ad esempio, un Post ha più Comment.

Definizione della relazione

<?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 assume che la tabella comments abbia una colonna post_id.

Recupero dei dati correlati

Una relazione hasMany restituisce una collection.
$post = Post::find(1);

foreach ($post->comments as $comment) {
    echo $comment->body;
}
Puoi anche aggiungere condizioni alla query.
$recentComments = Post::find(1)
    ->comments()
    ->latest()
    ->take(5)
    ->get();

Relazione inversa (belongsTo)

Per riferirsi al post da un commento, definisci belongsTo sul modello Comment.
<?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);
    }
}
$comment = Comment::find(1);
echo $comment->post->title;

belongsToMany (molti-a-molti)

La relazione molti-a-molti si usa quando entrambi i modelli hanno molteplici associazioni tra loro. Ad esempio, un Post ha più Tag e un Tag appartiene a più Post.

Struttura delle tabelle

Il molti-a-molti richiede una tabella pivot. Per Post e Tag prepara la tabella pivot post_tag.
posts
    id - integer
    title - string

tags
    id - integer
    name - string

post_tag
    post_id - integer
    tag_id - integer
Il nome della tabella pivot viene dedotto automaticamente concatenando in ordine alfabetico i nomi dei due modelli correlati (post + tagpost_tag).

Definizione della relazione

<?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);
    }
}
Definendola in modo analogo anche sul lato Tag puoi navigare la relazione anche nel verso opposto.
<?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);
    }
}

Recupero dei dati correlati

$post = Post::find(1);

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

Aggiungere e rimuovere associazioni

Con attach aggiungi un record nella tabella pivot, con detach lo rimuovi.
$post = Post::find(1);

// Aggiungi un tag
$post->tags()->attach($tagId);

// Rimuovi un tag
$post->tags()->detach($tagId);

// Sostituisce completamente le associazioni correnti
$post->tags()->sync([$tagId1, $tagId2]);
Con sync i record della tabella pivot che non corrispondono agli ID passati vengono eliminati automaticamente, lasciando solo quelli indicati.

Eager loading

Cos’è il problema N+1

Accedendo a una relazione come proprietà, Eloquent emette una query ogni volta. Questo è il “lazy loading”. Se accedi alla relazione in un ciclo, incorri nel problema N+1.
// Una query per recuperare tutti i post
$posts = Post::all();

foreach ($posts as $post) {
    // Per ogni post viene emessa una query per ottenere l'utente (N volte)
    echo $post->user->name;
}
Con 100 post fai 101 query in totale. Ha un forte impatto sulle prestazioni.

Eager loading con with()

Con il metodo with() recuperi in blocco i dati correlati. Le query si riducono a due.
// Recupera post e utenti in due query
$posts = Post::with('user')->get();

foreach ($posts as $post) {
    // Non vengono emesse query aggiuntive
    echo $post->user->name;
}
L’SQL eseguito è solo questo:
select * from posts

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

Eager load di più relazioni contemporaneamente

Puoi indicare più relazioni con un array.
$posts = Post::with(['user', 'comments', 'tags'])->get();

Eager load annidato

Con la notazione dot puoi fare eager load anche di relazioni annidate.
// Eager load dei commenti dei post e degli utenti di ciascun commento
$posts = Post::with('comments.user')->get();
L’eager loading è fondamentale per prevenire il problema N+1. Prendi l’abitudine di usare with() ogni volta che accedi a relazioni all’interno di un ciclo.

Prossimi passi

Introduzione a Eloquent

Ripassa le operazioni CRUD di base di Eloquent.
Ultima modifica il 13 luglio 2026