查询生成器 when() 方法产生条件错误的查询

Posted

技术标签:

【中文标题】查询生成器 when() 方法产生条件错误的查询【英文标题】:Query builder when() method producing wrongly conditioned query 【发布时间】:2021-12-13 17:43:47 【问题描述】:

我发布了我认为是 Laravel 错误 (https://github.com/laravel/framework/issues/39398) 但它已关闭,因为我不是 100% 认为它确实是一个错误。其他人能否告诉我这种行为是否错误?

我有以下代码:

$user=251;
$description='created';
Activity::when($user, function ($query, $user) 
    return $query->where('causer_id', $user)
    ->orWhere(function($query) use ($user) 
        $query->where('subject_id', $user)
        ->where('subject_type', "App\\User");
    );
)->when($description, function ($query, $description) 
    return $query->where('description', $description);
);

从逻辑上讲,我认为它应该生成一个查询,该查询返回具有正确用户和正确描述的所有行,但无论描述如何,我都会获得该用户的所有行。

上面的代码产生了这个 sql 查询:

select * from activity_log where causer_id = '251' or (subject_id = '251' and subject_type = 'App\User') and description = 'created'

...而我认为它应该产生:

select * from activity_log where (causer_id = '251' or (subject_id = '251' and subject_type = 'App\User')) and (description = 'created')

简而言之:when() 函数不应该在返回的结果周围加上括号以不影响查询的其他部分吗?它不是一个错误吗?

【问题讨论】:

【参考方案1】:

我不认为这是一个错误。这不是被破坏的预期行为。这将是添加到框架中的一项新功能。您可以访问 discord 服务器并尝试提出您的理由,或者只是提交一个 PR 并进行更改并为之辩护,但这并不是“破坏”现有功能。

when() 方法只是语法糖,因此您可以有条件地修改方法链中的查询,而无需分解为单独的 if 语句。下面的代码是等价的:

$query = Activity::query();

if ($user) 
    $query->where('causer_id', $user)
        ->orWhere(function($query) use ($user) 
            $query->where('subject_id', $user)
                ->where('subject_type', "App\\User");
        );


if ($description) 
    $query->where('description', $description);

正如您在上面的代码中看到的那样,不希望有条件添加的任何子句都包含在括号中(除非在您的 orWhere() 调用中明确指定)。

您所期望的一个问题是when() 方法可用于以任何方式修改查询,而不仅仅是添加额外的条件。那么,如果您在 when() 子句中添加了 orderBy()limit(),您期望会发生什么?

因此,when() 方法本身不会修改您的查询,但它会完全按照您的指示运行。因此,要执行您要查找的内容,您需要自己将查询包装在 when() 子句中:

Activity::when($user, function ($query, $user) 
              return $query->where(function($query) use ($user) 
                  return $query->where('causer_id', $user)
                               ->orWhere(function($query) use ($user) 
                                   $query->where('subject_id', $user)
                                         ->where('subject_type', "App\\User");
                               );
              );
       )
       ->when($description, function ($query, $description) 
           return $query->where('description', $description);
       );

【讨论】:

好的。看完你说的,我意识到我错了。当然 when() 不应该影响查询。但有一件事是,这在文档中可能会更清楚。但我现在停止抱怨:-)

以上是关于查询生成器 when() 方法产生条件错误的查询的主要内容,如果未能解决你的问题,请参考以下文章

select case when,用来判断查询

Laravel 查询构建器条件与当前查询使用时

查询多个结果是用case when 条件显示列的查询效率高,还是查询后union all合并效率高.

数组赋值理解错误,造成数据错误

php Laravel条件查询使用When

这两个case when end的条件语句查询结果为啥不一致