He encontrado que el concepto y el significado detrás de estos métodos son un poco confusos, ¿es posible que alguien me explique cuál es la diferencia entre has
y with
en el contexto de un ejemplo (si es posible)?
He encontrado que el concepto y el significado detrás de estos métodos son un poco confusos, ¿es posible que alguien me explique cuál es la diferencia entre has
y with
en el contexto de un ejemplo (si es posible)?
Respuestas:
with()
es para cargar con ganas . Eso básicamente significa que, a lo largo del modelo principal, Laravel precargará las relaciones que especifique. Esto es especialmente útil si tiene una colección de modelos y desea cargar una relación para todos ellos. Porque con la carga ansiosa, ejecuta solo una consulta de base de datos adicional en lugar de una para cada modelo de la colección.
Ejemplo:
User > hasMany > Post
$users = User::with('posts')->get();
foreach($users as $user){
$users->posts; // posts is already loaded and no additional DB query is run
}
has()
es filtrar el modelo de selección en función de una relación. Por lo tanto, actúa de manera muy similar a una condición normal de WHERE. Si solo usa has('relation')
eso significa que solo quiere obtener los modelos que tienen al menos un modelo relacionado en esta relación.
Ejemplo:
User > hasMany > Post
$users = User::has('posts')->get();
// only users that have at least one post are contained in the collection
whereHas()
funciona básicamente igual has()
pero le permite especificar filtros adicionales para que el modelo relacionado los verifique.
Ejemplo:
User > hasMany > Post
$users = User::whereHas('posts', function($q){
$q->where('created_at', '>=', '2015-01-01 00:00:00');
})->get();
// only users that have posts from 2015 on forward are returned
whereHas
en la relación del usuario al consultar la publicación.
whereHas
se usa usa el use Illuminate\Database\Eloquent\Builder;
que luego está con function(Builder $query)
. La mayoría de los ejemplos que he visto, utilizan puntos Builder
, simplemente pasan la consulta $, ¿cuál es la forma correcta?
El documento ya ha explicado el uso. Entonces estoy usando SQL para explicar estos métodos
Asumiendo que hay un Order (orders)
tiene muchos OrderItem (order_items)
.
Y ya has construido la relación entre ellos.
// App\Models\Order:
public function orderItems() {
return $this->hasMany('App\Models\OrderItem', 'order_id', 'id');
}
Estos tres métodos se basan en una relación .
Resultado: with()
devuelve el objeto modelo y sus resultados relacionados.
Ventaja: es una carga ansiosa que puede evitar el problema de N + 1 .
Cuando está utilizando el siguiente Eloquent Builder:
Order::with('orderItems')->get();
Laravel cambia este código a solo dos SQL :
// get all orders:
SELECT * FROM orders;
// get the order_items based on the orders' id above
SELECT * FROM order_items WHERE order_items.order_id IN (1,2,3,4...);
Y luego laravel fusiona los resultados del segundo SQL como diferentes de los resultados del primer SQL por clave externa . Por fin devolver los resultados de la colección.
Entonces, si seleccionó columnas sin la tecla Foreign_key en cierre, el resultado de la relación estará vacío:
Order::with(['orderItems' => function($query) {
// $query->sum('quantity');
$query->select('quantity'); // without `order_id`
}
])->get();
#=> result:
[{ id: 1,
code: '00001',
orderItems: [], // <== is empty
},{
id: 2,
code: '00002',
orderItems: [], // <== is empty
}...
}]
Has
devolverá el objeto del modelo de que su relación no está vacía .
Order::has('orderItems')->get();
Laravel cambia este código a un SQL :
select * from `orders` where exists (
select * from `order_items` where `order`.`id` = `order_item`.`order_id`
)
whereHas
y orWhereHas
métodos para poner where
condiciones a sus has
consultas. Estos métodos le permiten agregar restricciones personalizadas a una restricción de relación .
Order::whereHas('orderItems', function($query) {
$query->where('status', 1);
})->get();
Laravel cambia este código a un SQL :
select * from `orders` where exists (
select *
from `order_items`
where `orders`.`id` = `order_items`.`order_id` and `status` = 1
)
with('relation')
incluirá los datos de la tabla relacionada en la colección devuelta,has('relation')
ywhereHas('relation')
será no incluir datos de la tabla relacionada. Por lo tanto, es posible que tenga que llamar a amboswith('relation')
, así como ahas()
owhereHas()
.