Laravel - Eloquente "Tem", "Com", "Onde tem" - O que eles significam?

210

Eu achei o conceito e o significado por trás desses métodos um pouco confusos. É possível que alguém me explique qual é a diferença entre hase withno contexto de um exemplo (se possível)?

lukasgeiter
fonte

Respostas:

553

Com

with()é para carregamento ansioso . Isso basicamente significa que, ao longo do modelo principal, o Laravel pré-carregará o (s) relacionamento (s) que você especificar. Isso é especialmente útil se você tiver uma coleção de modelos e desejar carregar uma relação para todos eles. Porque, com o carregamento rápido, você executa apenas uma consulta adicional ao banco de dados, em vez de uma para cada modelo na coleção.

Exemplo:

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
}

Tem

has()é filtrar o modelo de seleção com base em um relacionamento. Por isso, atua de maneira muito semelhante a uma condição WHERE normal. Se você apenas usar has('relation')isso significa que deseja obter apenas os modelos que possuem pelo menos um modelo relacionado nessa relação.

Exemplo:

User > hasMany > Post

$users = User::has('posts')->get();
// only users that have at least one post are contained in the collection

Onde tem

whereHas()funciona basicamente da mesma maneira que has()permite especificar filtros adicionais para o modelo relacionado verificar.

Exemplo:

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
fonte
101
+1, resposta muito útil! Note-se também que, enquanto with('relation')vai incluir os dados de tabela a relacionada na coleção retornada, has('relation')e whereHas('relation')vai não incluem os dados de tabela a relacionado. Portanto, pode ser necessário ligar para ambos with('relation'), bem como has()ou whereHas().
Soulriser 6/02/16
1
Greet Resposta, Como modelo pai acesso a partir de modelo de relacionamento, por exemplo, aqui como procurar modelo pós com base nos atributos do modelo de usuário
hussainfrotan
@BhojendraNepal Infelizmente, não parece haver muito sobre isso nos documentos ... Isso é tudo que eu encontrei (
faltam
@hussainfrotan da mesma maneira, use whereHasna relação do usuário ao consultar uma postagem.
Michael Tsang
Curioso, na documentação do Laravel: laravel.com/docs/5.8/eloquent-relationships , ao usá- whereHaslo, usa o use Illuminate\Database\Eloquent\Builder;que então está com function(Builder $query). A maioria dos exemplos que eu vi, dot usa o Builder, basta passar na consulta $, qual é o caminho certo?
Guntar 22/02
8

O documento já explica o uso. Então, eu estou usando o SQL para explicar esses métodos

Exemplo:


Supondo que haja um Order (orders)tem muitos OrderItem (order_items).

E você já construiu o relacionamento entre eles.

// App\Models\Order:
public function orderItems() {
    return $this->hasMany('App\Models\OrderItem', 'order_id', 'id');
}

Esses três métodos são todos baseados em um relacionamento .

Com


Resultado: with() retorna o objeto de modelo e seus resultados relacionados.

Vantagem: O carregamento é rápido, o que pode impedir o problema N + 1 .

Quando você estiver usando o seguinte Eloquent Builder:

Order::with('orderItems')->get();

O Laravel altera esse código para apenas dois 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...);

E então o laravel mescla os resultados do segundo SQL como diferentes dos resultados do primeiro SQL por chave estrangeira . Por fim, retorne os resultados da coleção.

Portanto, se você selecionou colunas sem a chave estrangeira no fechamento, o resultado do relacionamento ficará vazio:

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

Tem


Hasretornará ao objeto do modelo que seu relacionamento não está vazio .

Order::has('orderItems')->get();

O Laravel altera esse código para um SQL :

select * from `orders` where exists (
    select * from `order_items` where `order`.`id` = `order_item`.`order_id`
)

Onde tem


whereHase orWhereHasmétodos para colocar wherecondições em suas hasconsultas. Esses métodos permitem adicionar restrições personalizadas a uma restrição de relacionamento .

Order::whereHas('orderItems', function($query) {
   $query->where('status', 1);
})->get();

O Laravel altera esse código para um SQL :

select * from `orders` where exists (
    select * 
    from `order_items` 
    where `orders`.`id` = `order_items`.`order_id` and `status` = 1
)
TsaiKoga
fonte