laravel框架中,模型中的whereHas和with有什么区别?

在 Laravel 模型中,whereHaswith 都是处理关联关系的重要方法,但它们的作用和使用场景有明显区别:

1. whereHas 方法

作用:用于筛选出满足关联条件的主模型数据,本质是对主模型进行过滤。

原理

  • 会生成 SQL 的 WHERE EXISTS 子句或 INNER JOIN,通过关联表的条件来限制主模型的查询结果。
  • 不会预加载关联数据,只用于筛选主模型。

示例
假设存在 Post 模型(文章)和 Comment 模型(评论),关联关系为 Post 有多个 Comment

// 筛选出有评论的文章(主模型是Post)
$posts = Post::whereHas('comments', function ($query) {
    $query->where('content', 'like', '%laravel%'); // 评论内容包含laravel
})->get();

上面代码会查询出所有包含“laravel”评论的文章,但不会获取这些评论的具体数据。

2. with 方法

作用:用于预加载关联数据,解决“N+1 查询问题”,提高查询效率。

原理

  • 会先查询主模型数据,再根据主模型的关联外键批量查询关联数据(通常是 2 条 SQL)。
  • 不会筛选主模型,只是提前加载关联数据,避免后续访问关联时重复查询数据库。

示例

// 预加载文章的所有评论(不会筛选文章,只是加载关联)
$posts = Post::with('comments')->get();

// 访问关联数据时不会再查询数据库
foreach ($posts as $post) {
    echo $post->comments; // 已预加载,直接使用
}

核心区别

维度whereHaswith
作用筛选主模型(基于关联条件)预加载关联数据(不筛选主模型)
生成的 SQLWHERE EXISTS 或关联条件的查询主模型查询 + 关联数据批量查询
结果影响影响主模型的查询结果(数量可能减少)不影响主模型数量,仅附加关联数据
典型场景需要根据关联数据过滤主模型时需要高效访问关联数据时

结合使用

两者可以结合使用,实现“筛选主模型 + 预加载关联数据”:

// 筛选有符合条件评论的文章,并预加载这些评论
$posts = Post::whereHas('comments', function ($query) {
    $query->where('content', 'like', '%laravel%');
})->with(['comments' => function ($query) {
    $query->where('content', 'like', '%laravel%'); // 只加载符合条件的评论
}])->get();

简单来说:whereHas 是“筛选主模型”,with 是“预加载关联”,两者常配合使用但职责不同。

那是否可以将whereHas去掉,只保留with

因为两者的使用场景不一样,因此能不能直接去掉 whereHas 只保留 with,要根据使用场景实际决定,因为两者的作用完全不同,去掉后会导致查询结果发生变化。

具体分析:

  1. 保留 whereHas + with 的效果

    • whereHas筛选出有“包含laravel的评论”的文章(主模型被过滤)。
    • with为这些筛选后的文章,只加载“包含laravel的评论”(关联数据被过滤)。
    • 最终结果:只有符合条件的文章,且文章中只包含符合条件的评论
  2. 去掉 whereHas 只保留 with 的效果

    // 只保留with的情况
    $posts = Post::with(['comments' => function ($query) {
        $query->where('content', 'like', '%laravel%');
    }])->get();
    
    • 此时不会筛选文章(所有文章都会被查询出来,包括没有任何评论的文章)。
    • 对于每篇文章,只加载符合条件的评论(如果文章没有符合条件的评论,comments 会是一个空集合)。
    • 最终结果:所有文章,且每篇文章中只包含符合条件的评论(可能为空)

结论:

如果你的需求是 “只获取有符合条件评论的文章,并且只加载这些符合条件的评论” ,就必须保留 whereHas

如果去掉 whereHas,会导致结果中包含所有文章(包括没有符合条件评论的文章),这与原代码的逻辑不符。

两者的配合是“先筛选主模型,再过滤关联数据”,缺一不可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值