Laravel 带过滤器的复杂查询,具有雄辩的

Laravel 带过滤器的复杂查询,具有雄辩的,laravel,eloquent,laravel-5.2,Laravel,Eloquent,Laravel 5.2,我有以下表格(和相关字段): 现在,我使用多个并发过滤器生成了一些报告: 公司名称、用户名、产品 我希望公司成为结果中的“顶级”对象。 所以 然后 这已经够复杂了,我还想加载所有 关系,以优化数据库访问,因此我最终得出以下结论: $cond = function($q) use ($user_name) { $cond2 = function ($q2) use ($user_name) { $q2->where('name', 'LIKE', "%$user_na

我有以下表格(和相关字段):

现在,我使用多个并发过滤器生成了一些报告: 公司名称、用户名、产品

我希望公司成为结果中的“顶级”对象。 所以

然后

这已经够复杂了,我还想加载所有 关系,以优化数据库访问,因此我最终得出以下结论:

$cond = function($q) use ($user_name) {
    $cond2 = function ($q2) use ($user_name) {
        $q2->where('name', 'LIKE', "%$user_name%");
    };

    $q->whereHas('user', $cond2)
      ->with(['user' => $cond2]);
};
Company::where('name', 'LIKE', "%$company_name%")
    ->whereHas('sales', $cond)
    ->with(['sales' => $cond]);
我觉得这会带来不必要的重复。此外,在过滤时 同样的方式,我认为热切的加载取代了之前的加载

所以。。。做这件事最好的方法是什么?
我可以为此使用Eloquent,还是应该返回到“原始”查询?

您可以使用检查Eloquent生成的查询。如果查询看起来“不太理想”,则可以考虑原始查询。

如果你的查询是最优的,但雄辩的语法看起来太“凌乱”,你可以考虑将部分部分建立在你的模型中。 例如,您可以在

Sales
模型中定义一个范围以匹配名称:

class Sales extends Model
{
    /**
     * Scope a query to only include Sales for users with a matching name.
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeMatchUserName($query, $user_name)
    {
        $cond2 = function ($q2) use ($user_name) {
            $q2->where('name', 'LIKE', "%$user_name%");
        };

        return $query->with(['user' => $cond2])
                     ->whereHas('user', $cond2);
    }
}
然后您的查询变得更简单(看起来):

您甚至可以将该查询打包到您的
公司
模型中:

class Company extends Model
{
    /**
     * Scope a query to only include Companies and Sales for a matching user and company name.
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeMatchCompanyAndUserName($query, $user_name, $company_name)
    {
        $cond = function($q) use ($user_name) {
            return $q->matchUserName($user_name);
        };

        return $query->where('name', 'LIKE', "%$company_name%")
            ->with(['sales' => $cond])
            ->whereHas('sales', $cond);
    }
}
那么你所需要做的就是:

Company::matchCompanyAndUserName($user_name, $company_name);

谢谢+1用于
getQueryLog
技巧,也用于scopes思想(可能是封装一些过滤逻辑的好地方)。然而,我认为,当使用
快速加载时,where has
的第一件事是不必要的。嗯,那么,
Sales
如果没有任何匹配的用户,那么应该从结果中完全忽略?是的,在这种情况下,我只想生成一个报告,对每个用户的销售额进行过滤。好的,在这种情况下,可能还有另一种方法不需要您运行两次过滤器。让我考虑一下。如果您在加载集合后使用
with
尝试该集合,会怎么样?然后,您可以消除任何没有匹配用户的
销售
。由于
wherehads
子句,我相信这将为您节省一个额外的查询。
class Sales extends Model
{
    /**
     * Scope a query to only include Sales for users with a matching name.
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeMatchUserName($query, $user_name)
    {
        $cond2 = function ($q2) use ($user_name) {
            $q2->where('name', 'LIKE', "%$user_name%");
        };

        return $query->with(['user' => $cond2])
                     ->whereHas('user', $cond2);
    }
}
$cond = function($q) use ($user_name) {
    return $q->matchUserName($user_name);
};

Company::where('name', 'LIKE', "%$company_name%")
    ->with(['sales' => $cond])
    ->whereHas('sales', $cond);
class Company extends Model
{
    /**
     * Scope a query to only include Companies and Sales for a matching user and company name.
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeMatchCompanyAndUserName($query, $user_name, $company_name)
    {
        $cond = function($q) use ($user_name) {
            return $q->matchUserName($user_name);
        };

        return $query->where('name', 'LIKE', "%$company_name%")
            ->with(['sales' => $cond])
            ->whereHas('sales', $cond);
    }
}
Company::matchCompanyAndUserName($user_name, $company_name);