在 Laravel 5 中合并“with”和“whereHas”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29591931/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 11:20:38  来源:igfitidea点击:

Merge 'with' and 'whereHas' in Laravel 5

phplaraveleloquentlaravel-5

提问by KristofMorva

I have this code in Laravel 5, using Eloquent, which is working perfectly:

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

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

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

Basically the goal is to get only those users with their filtered submissions, which has any of them. However, it seems wasting to run both whereHasand withmethods with the same callback function. Is there a way to simplify it?

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

Thanks.

谢谢。

回答by lukasgeiter

In terms of performance you can't really optimize anything here (except if you were to move from eloquent relations to joins). With or without whereHas, two queries will be run. One to select all users another one to load the related models. When you add the whereHascondition a subquery is added, but it's still two queries.

就性能而言,您无法真正优化这里的任何内容(除非您要从雄辩的关系转向连接)。有或没有whereHas,将运行两个查询。一个选择所有用户,另一个加载相关模型。添加whereHas条件时,会添加一个子查询,但它仍然是两个查询。

However, syntactically you could optimize this a bit by adding a query scopeto your model (or even a base model if you want to use this more often):

但是,从语法上讲,您可以通过向模型添加查询范围(如果您想更频繁地使用它,甚至可以添加基本模型)来对此进行优化:

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

Usage:

用法:

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

回答by Ijas Ameenudeen

The 'macroable' way (Laravel 5.4+)

' macroable' 方式(Laravel 5.4+

Add this inside a service provider's boot()method.

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

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

回答by Emsal

I want to extend the answer from @lukasgeiter using static functions.

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

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

Usage is the same

用法是一样的

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