Laravel - Eloquent"Has","With","WhereHas" - 它们是什么意思?

184 orm relational-database relationship laravel eloquent

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

luk*_*ter 487

with()是为了急切加载.这基本上意味着,沿着主模型,Laravel将预先加载您指定的关系.如果您有一组模型并且想要为所有模型加载关系,这将特别有用.因为通过急切加载,您只能为集合中的每个模型运行一个额外的数据库查询,而不是一个.

例:

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
}
Run Code Online (Sandbox Code Playgroud)

具有

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

  • +1,非常有帮助的答案!还要注意,虽然`with('relation')`将在返回的集合中包含相关表的数据,`has('relation')`和`whereHas('relation')`将*不包括相关表的数据.所以你可能需要调用`with('relation')`以及`has()`或`whereHas()`. (81认同)
  • 欢迎回答,如何从关系模型访问父模型,例如这里如何根据用户模型的属性搜索帖子模型 (2认同)

Tsa*_*oga 36

文档已经说明了用法。所以我用SQL来解释这些方法

例子:


假设有一个Order (orders)has many OrderItem (order_items)

而你已经建立了他们之间的关系。

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

这三种方法都是基于一种关系


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

优点:eager-loading,可以防止N+1问题

当您使用以下 Eloquent Builder 时:

Order::with('orderItems')->get();
Run Code Online (Sandbox Code Playgroud)

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...);
Run Code Online (Sandbox Code Playgroud)

然后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
  }...
}]
Run Code Online (Sandbox Code Playgroud)


Has将返回其关系不为空的模型对象。

Order::has('orderItems')->get();
Run Code Online (Sandbox Code Playgroud)

Laravel 将此代码更改为一个 SQL

select * from `orders` where exists (
    select * from `order_items` where `orders`.`id` = `order_items`.`order_id`
)
Run Code Online (Sandbox Code Playgroud)

哪里有


whereHas以及对查询orWhereHas设置where条件的方法has。这些方法允许您向关系约束添加自定义约束

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

Laravel 将此代码更改为一个 SQL

select * from `orders` where exists (
    select * 
    from `order_items` 
    where `orders`.`id` = `order_items`.`order_id` and `status` = 1
)
Run Code Online (Sandbox Code Playgroud)