Aprende a definir con Eloquent las relaciones entre tablas (uno a uno, uno a muchos y muchos a muchos) y a obtener los datos relacionados de forma eficiente.
Las tablas de una base de datos suelen estar relacionadas entre sí. Por ejemplo, un post de un blog puede tener múltiples comentarios, o un pedido está asociado al usuario que lo realizó.Eloquent facilita la definición y la manipulación de esas relaciones entre tablas. Cada relación se define como un método del modelo Eloquent.
Esta página utiliza modelos concretos como User, Post, Comment y Tag a modo de ejemplo.
Se asume que dichos modelos y sus tablas ya están creados.
Las principales relaciones que soporta Eloquent son:
Relación
Descripción
hasOne
Uno a uno (el padre tiene un único hijo)
belongsTo
Inversa del uno a uno (el hijo pertenece al padre)
<?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 infiere la clave foránea a partir del nombre del modelo padre. En este caso, asume que la tabla profiles contiene la columna user_id.
Puedes acceder a la relación como si fuera una propiedad.
$user = User::find(1);$profile = $user->profile;
Al acceder al método de relación como si fuera una propiedad, Eloquent lanza automáticamente la consulta y te devuelve los datos relacionados. A esto se le llama «propiedad dinámica de relación».
<?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 asume que la tabla comments contiene la columna post_id.
Usa una relación muchos a muchos cuando ambos modelos pueden estar asociados a múltiples registros del otro lado. Por ejemplo, un Post tiene varios Tag y cada Tag pertenece a varios Post.
<?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); }}
Si defines lo mismo en el modelo Tag, puedes acceder a los datos en sentido inverso.
<?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); }}
attach añade un registro a la tabla pivote y detach lo elimina.
$post = Post::find(1);// Añadir etiqueta$post->tags()->attach($tagId);// Eliminar etiqueta$post->tags()->detach($tagId);// Reemplazar todas las relaciones actuales$post->tags()->sync([$tagId1, $tagId2]);
Con sync se eliminan automáticamente los registros de la tabla pivote que no estén en el array, dejando únicamente los IDs indicados como relaciones vigentes.
Al acceder a una relación como propiedad, Eloquent lanza una consulta cada vez. A esto se le llama «lazy loading» (carga perezosa). Si accedes a una relación dentro de un bucle, se produce el problema N+1.
// 1 consulta para obtener todos los posts$posts = Post::all();foreach ($posts as $post) { // Por cada post se ejecuta una consulta para obtener el usuario (N veces) echo $post->user->name;}
Con 100 posts se generarían 101 consultas en total, con el consiguiente impacto en el rendimiento.
Con el método with() puedes obtener los datos relacionados de una sola vez, reduciendo el total a solo 2 consultas.
// Los posts y sus usuarios en 2 consultas$posts = Post::with('user')->get();foreach ($posts as $post) { // Ya no se lanzan consultas adicionales echo $post->user->name;}
Solo se ejecutan estas 2 sentencias SQL:
select * from postsselect * from users where id in (1, 2, 3, ...)