Laravel -雄辩的“;Has";With";-什么意思?

我发现这些方法背后的概念和意义有点令人困惑,是否有人可以向我解释一下haswith之间的区别是什么,在一个例子的上下文中(如果可能)?

500683 次浏览

with()代表立即加载。这基本上意味着,沿着主模型,Laravel将预加载您指定的关系。如果您有一个模型集合,并且希望为所有模型加载一个关系,那么这将特别有用。因为使用即时加载,您只运行一个额外的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()是根据关系筛选选择模型。所以它的作用和正常的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

文档已经解释了用法,所以我将使用SQL来解释这些方法。

例子:

假设有一个Order (orders)有多个OrderItem (order_items),并且你已经建立了它们之间的关系:

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

这三个方法是一切都基于一段关系

结果: with()返回模型对象及其相关结果。

优势:它是立即加载,可以防止N+1问题

当你使用以下雄辩的建设者:

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的结果合并,最后返回收集结果。

所以如果你在闭包中选择了没有foreign_key的列,关系结果将为空:

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将返回模型的对象。

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

Laravel将此代码更改为一个SQL查询:

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

whereHas

方法whereHasorWhereHas对你的has查询设置了where条件。这些方法允许你添加自定义约束到关系约束

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
)