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 has
e with
no contexto de um exemplo (se possível)?
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 has
e with
no contexto de um exemplo (se possível)?
Respostas:
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
}
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
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
whereHas
na relação do usuário ao consultar uma postagem.
whereHas
lo, 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?
O documento já explica o uso. Então, eu estou usando o SQL para explicar esses métodos
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 .
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
}...
}]
Has
retornará 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`
)
whereHas
e orWhereHas
métodos para colocar where
condições em suas has
consultas. 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
)
with('relation')
vai incluir os dados de tabela a relacionada na coleção retornada,has('relation')
ewhereHas('relation')
vai não incluem os dados de tabela a relacionado. Portanto, pode ser necessário ligar para amboswith('relation')
, bem comohas()
ouwhereHas()
.