Siempre insistimos con usar la carga impaciente (Eager Loading) con el método with()
ya que nos permite cargar los registros relacionados con nuestro modelo:
public function books() { return $this->hasMany(Book::class); } $authors = Author::with('books')->get();
De esta forma obtenemos todos los autores con sus libros en una misma colección y con una consulta a la base de datos optimizada.
Pero en este tip vamos a ver que hay una forma automática de realizar lo mismo.
Cargar relaciones automáticamente
Hay situaciones en las que sabemos que cada vez que obtenemos un modelo, necesitamos su relación. Por este motivo, Laravel nos brinda una forma de automatizar la carga sin necesidad de utilizar el método with()
todo el tiempo.
Así que, si necesitamos cargar los libros de los autores cada vez que obtenemos estos últimos, tenemos que sobrescribir la propiedad $with
en el modelo Author
con los nombres de las relaciones que necesitamos cargar automáticamente. Por ejemplo.
class Author extends Model { protected $with = ['books']; public function books() { return $this->hasMany(Book::class); } // (...) }
De esta forma, cada vez que obtengamos uno o mas autores, vendrán cargados sus libros (si es que los tiene). Así que, si hacemos lo siguiente:
$author = Author::first(); $books = $author->books;
Atención: Cuidado con la carga automática
No todo es color de rosas, hay que tener en cuenta que si establecemos la propiedad $with
en el modelo, siempre, pero siempre, se cargaran las relaciones que establecimos en $with
.
Te aconsejo que analices correctamente tu sistema para asegurarte que la mayoría de veces que utilizas el modelo también utilizaras sus relaciones.
La buena noticia es que, si en alguna parte del sistema no necesitas la carga automática, podes utilizar el método without()
para no cargar la relación. Por ejemplo:
$relevantAuthors = Author::where('relevant', true)->withour('books')->get();
Bonus: Carga automática de cantidad de registros relacionados
No solo tenemos la propiedad $with
, también Laravel nos permite sobrescribir la propiedad $withCount
que nos permitirá obtener la cantidad de registros que tiene la relación. Por ejemplo:
class Author extends Model { protected $with = ['books']; protected $withCount = ['books']; public function books() { return $this->hasMany(Book::class); } // (...) } $author = Author::first(); {{ $author->books_count }}
Para obtener la cantidad de registros de los modelos relacionados automáticamente, primero debemos establecer en el arreglo de $withCount
, el nombre de la relación y luego hacer la carga automática (o la carga con el método with()
) .
Por ultimo, para mostrar la cantidad de registros debemos armar la propiedad con el nombre de la relación (books en nuestro caso) y luego la palabra _count
, como lo hicimos en el ejemplo anterior.
Pero ojo! $withCount
, como $with
, siempre se ejecutarán por más que no vayamos a utilizarlo.
Conclusión
Espero que les haya gustado este Laravel tip y utilízalo cuando sea necesario. Nos vemos en la próxima.
Genial! gracias, sigue asi
Muchas gracias!
Increíble que buen post como siempre, me dejo con una duda si estoy des actualizado, ya que yo no uso el with solo creo relaciones con los helpers hasmany() o belongsTo() en ambos modelos y esto me permite relacionarlos, creo que de la forma que lo colocas esta mas fácil,. mi pregunta es sera que estoy mal de la forma en que yo lo hacia? y otra pregunta cuando uso el método without() me imagino que también quita la carga del método withCount() no?
Hola Ariel, muchas gracias por tu comentario.
Esta bien que establezcas las relaciones con hasMany() y belongsTo(), es como se debe hacer. Lo que tal vez no estas haciendo bien es cuando llamas a las relaciones.
Por ejemplo, si haces esto:
Estas haciendo una consulta a la BD por cada vuelta del foreach, por lo tanto, si el autor tiene 10.000 libros, estarás haciendo 10.000 queries :/
El método with() sirve para evitar esto. Ya que, si haces esto:
Estarás haciendo una consulta a la BD (sin contar la consulta por el autor, obviamente).
Te acá toda la historia con el método with() jeje.
Con respecto a la segunda pregunta, no. Si utilizas without() no quita la carga withCount, la cantidad de registros relacionados seguirán viniendo.
No encontré un método para esto, pero lo voy a revisar o si alguien lo sabe, se agradece que lo dejen en los comentarios.
Saludos.
Hola muchas gracias, me han sido muy útiles varios tips, seguiré explorando
Una pequena acotacion, tambien hay que tener cuidado al usar el with en varios modelos que esten relacionados ya que podrias acabar con una relacion recursiva, es decir este modelo trae su relacion, que trae el modelo original, y asi infinitamente!
Muy buena aclaración! Gracias Javier.
Excelente, Laravel me gusta cada vez más, ahora es imposible acordarse de todo jajaja
Gracias! Si a mi también se me olvidan algunas cosas por eso hasta yo mismo consulto la web jajaj
Claro y útil.
Buenísimo.. me acabas de salvar, andaba buscando este tip hace un par de horas.. genial (Y)