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

13 浏览
0 Comments

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

我发现这些方法背后的概念和含义有些令人困惑,是否有人可以给我解释一下在示例的情况下haswith的区别是什么?

admin 更改状态以发布 2023年5月23日
0
0 Comments

文档已经解释了使用方法,因此我将使用 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

方法 whereHasorWhereHaswhere 条件放置在您的 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
)

0
0 Comments

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

0