Laravel - Eloquent “Has”,“With”,“WhereHas” - 它们是什么意思?
Laravel - Eloquent “Has”,“With”,“WhereHas” - 它们是什么意思?
我发现这些方法背后的概念和含义有些令人困惑,是否有人可以给我解释一下在示例的情况下has
和with
的区别是什么?
文档已经解释了使用方法,因此我将使用 SQL 来解释这些方法。
示例:
假设存在一个 Order (orders)
拥有多个 OrderItem (order_items)
,并且你已经建立了它们之间的关系:
// App\Models\Order: public function orderItems() { return $this->hasMany('App\Models\OrderItem', 'order_id', 'id'); }
这三种方法都是基于关联关系的。
with
结果:with()
返回模型对象及其相关结果。
优点:它是急切加载,可以防止 N+1 问题。
当使用以下 Eloquent Builder 时:
Order::with('orderItems')->get();
Laravel 将此代码更改为只有两个 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...);
然后 Laravel 通过外键将第二个 SQL 查询的结果与第一个 SQL 查询的结果合并,最终返回集合结果。
因此,如果在闭包中选择不包含外键的列,则关系结果将为空:
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
Has
方法将在关联关系不为空时返回模型对象。
Order::has('orderItems')->get();
Laravel 将此代码更改为一个 SQL 查询:
select * from `orders` where exists ( select * from `order_items` where `orders`.`id` = `order_items`.`order_id` )
whereHas
方法 whereHas
和 orWhereHas
将 where
条件放置在您的 has
查询中。这些方法允许您为关系约束添加自定义约束条件。
Order::whereHas('orderItems', function($query) { $query->where('status', 1); })->get();
Laravel会将这段代码修改成一个SQL查询:
select * from `orders` where exists ( select * from `order_items` where `orders`.`id` = `order_items`.`order_id` and `status` = 1 )
With
with()
用于渴望加载。这基本上意味着,除了主要模型之外,Laravel将预加载您指定的关系(s)。如果您有一组模型并且想要为所有模型加载关系,则特别有帮助。因为使用急切加载只运行一个附加的DB查询,而不是集合中每个模型的查询都运行一个。
例如:
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
has()
是基于关系过滤选择模型的。因此,它的行为非常类似于常规的WHERE条件。如果只使用has('relation')
,这意味着您只想获取在此关系中至少有一个相关模型的模型。
例如:
User > hasMany > Post
$users = User::has('posts')->get(); // only users that have at least one post are contained in the collection
WhereHas
whereHas()
基本上与has()
相同,但允许您为要检查的相关模型指定其他过滤器。
例如:
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