Laravel - Eloquent "Has", "With", "WhereHas" - ¿Qué significan?

212

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 hasy withen el contexto de un ejemplo (si es posible)?

lukasgeiter
fuente

Respuestas:

558

Con

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
}

Tiene

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

Donde tiene

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
lukasgeiter
fuente
101
+1, respuesta muy útil! Tenga en cuenta también que, si bien with('relation')incluirá los datos de la tabla relacionada en la colección devuelta, has('relation')y whereHas('relation')será no incluir datos de la tabla relacionada. Por lo tanto, es posible que tenga que llamar a ambos with('relation'), así como a has()o whereHas().
Soulriser
1
Salude la respuesta, Cómo acceder al modelo principal desde el modelo de relación, por ejemplo, aquí cómo buscar el modelo de publicación basado en los atributos del modelo de usuario
hussainfrotan
@BhojendraNepal Desafortunadamente, no parece haber mucho al respecto en los documentos ... Esto es todo lo que encontré (
faltan
@hussainfrotan de la misma manera, utilícelo whereHasen la relación del usuario al consultar la publicación.
Michael Tsang
Curioso, en la documentación de Laravel: laravel.com/docs/5.8/eloquent-relationships , cuando whereHasse 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?
Guntar
8

El documento ya ha explicado el uso. Entonces estoy usando SQL para explicar estos métodos

Ejemplo:


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 .

Con


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
  }...
}]

Tiene


Hasdevolverá 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`
)

donde tiene


whereHasy orWhereHasmétodos para poner wherecondiciones a sus hasconsultas. 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
)
TsaiKoga
fuente