带有Eloquent过滤器的复杂查询

时间:2016-03-21 13:52:13

标签: laravel eloquent laravel-5.2

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

users           (id, name)
companies       (id, name)
sales           (id, company_id, user_id)
products        (id, description)
products_sales  (id, product_id, sale_id)

现在,我有一些带有多个并发过滤器的报告生成: 公司名称,用户名,产品。

我希望公司成为最高级别的公司。结果中的对象。 所以,

Company::where('name', 'LIKE', "%$company_name%")

然后

  ->whereHas('sales', function ($query) use ($user_name) {
      $query->whereHas('user', function ($query2) use ($user_name) {
          $query2->where('name', 'LIKE', "%$user_name%")
      });
  });

这已经足够复杂了,我也希望加载所有 关系,以优化数据库访问,所以我最终得到:

$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吗?或者我应该回到原始的'查询?

1 个答案:

答案 0 :(得分:1)

您可以使用getQueryLog检查Eloquent生成的查询。如果您的查询看起来不是最佳",您可能会考虑原始查询。

如果您的查询是最佳的,但Eloquent语法看起来太乱了"凌乱",您可以考虑在模型中构建部分query scopes

例如,您可以在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);
    }
}

然后你的查询变得更简单(看起来):

$cond = function($q) use ($user_name) {
    return $q->matchUserName($user_name);
};

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

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

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);