在 Laravel 5 中合并 'with' 和 'whereHas'

Posted

技术标签:

【中文标题】在 Laravel 5 中合并 \'with\' 和 \'whereHas\'【英文标题】:Merge 'with' and 'whereHas' in Laravel 5在 Laravel 5 中合并 'with' 和 'whereHas' 【发布时间】:2015-06-17 23:20:56 【问题描述】:

我在 Laravel 5 中有这段代码,使用 Eloquent,运行良好:

$filterTask = function($query) use ($id) 
    $query->where('taskid', $id);
;

User::whereHas('submissions', $filterTask)->with(['submissions' => $filterTask])->get();

基本上,目标是只获取那些提交过滤后的提交的用户,其中任何一个都有。 但是,使用相同的回调函数同时运行 whereHaswith 方法似乎很浪费。有没有办法简化它?

谢谢。

【问题讨论】:

不,没有其他方法(使用雄辩的关系查询 ofc)。为什么会浪费? 好吧,因为我们要过滤两次提交的条件;我只是希望有一种解决方案可以使它成为一个查询而不是更多,但是@lukasgeiter 说得很清楚。 为什么这个答案票数太少? 【参考方案1】:

就性能而言,您在这里无法真正优化任何东西(除非您要从 eloquent 关系转移到连接)。不管有没有whereHas,都会运行两个查询。一个选择所有用户另一个加载相关模型。当您添加 whereHas 条件时,会添加一个子查询,但它仍然是两个查询。

但是,从语法上讲,您可以通过在模型中添加 query scope 来稍微优化一下(如果您想更频繁地使用它,甚至可以添加基本模型):

public function scopeWithAndWhereHas($query, $relation, $constraint)
    return $query->whereHas($relation, $constraint)
                 ->with([$relation => $constraint]);

用法:

User::withAndWhereHas('submissions', function($query) use ($id)
    $query->where('taskid', $id);
)->get();

【讨论】:

我有这个问题两天了,现在它就像一个魅力。 你拯救了我的一天谢谢 为了便于阅读,我可能也将其重命名为 withHas 我将它添加到一个特征中,我可以轻松地在我想要的所有模型中使用它。非常推荐!【参考方案2】:

我想使用静态函数扩展来自@lukasgeiter 的答案。

public static function withAndWhereHas($relation, $constraint)
    return (new static)->whereHas($relation, $constraint)
        ->with([$relation => $constraint]);

用法一样

User::withAndWhereHas('submissions', function($query) use ($id)
    $query->where('taskid', $id);
)->get();

【讨论】:

但在这种情况下,您不能将其与其他查询混合使用。这应该是您必须从模型中静态调用的第一个函数,但情况并非总是如此。【参考方案3】:

ma​​croable”方式(Laravel 5.4+

将此添加到服务提供者的boot() 方法中。

\Illuminate\Database\Eloquent\Builder\Eloquent::macro('withAndWhereHas', function($relation, $constraint)
    return $this->whereHas($relation, $constraint)->with([$relation => $constraint]);
);

【讨论】:

在 Laravel 5.8 中我必须这样做: \Illuminate\Database\Eloquent\Builder::macro('withAndWhereHas', function($relation, $constraint) return $this->whereHas($relation , $constraint)->with([$relation => $constraint]); );

以上是关于在 Laravel 5 中合并 'with' 和 'whereHas'的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Laravel 5 中对合并的集合进行分页?

Laravel (5.7) Eloquent Many to Many with query on双方

如何在 laravel 5.8 中合并两个 sql 表

Laravel 5.3 使用 with() 方法预先加载关系

有啥方法可以避免在 Laravel 5.7 Eloquent 中加载父级时加载这些 $with 模型?

Laravel 5.4 Webpack Mix - 合并SCSS和CSS