Laravel查询构建器 vs 原始查询

3

我是一名初学 Laravel 的人,目前我非常喜欢 Eloquent 和 QueryBuilder,但是当查询变得更加复杂时,我的头脑就开始疼痛...经过相当长的时间,我刚完成了两个可行的示例,也许你们可以帮助我进行优化。首先我将给出这两个示例,然后分别说明它们的 (不)优点。

首先是 DB::select... 说实话,我认为这比第二个示例更可读...或者可能是我没有正确地使用构建器 xD。

    $shared_slugs   = Magic::in_query($this->shared_slugs);

    $items = DB::select("
        SELECT * FROM f_admin_items
        WHERE
            active = 1
        AND (
            slug IN $shared_slugs
            OR
            :treshhold <= :urank AND id IN (SELECT admin_item_id FROM f_user_access WHERE user_id = :uid)
            OR
            :treshhold > :urank AND `rank` >= :urank
        )
        ORDER BY `order` ASC
    ", [
        'treshhold' => $this->threshold_rank,
        'urank' => $user_rank,
        'uid'    => $user_id
    ]);

总体而言,使用命名参数绑定非常有效。基本上,菜单项始终必须处于活动状态,加上(1或2或3)。例如,dashboard 被接受为共享 slug。否则,会进行一些排名检查。
现在我一直在努力尝试使用 eloquent en query builder =/ 实现此目的。我认为设置关系不是必要的,���为我只在菜单和中间件中使用它。在这种情况下,f_user_access 表仅包含 admin_item_id 和 user_id,不真正充当枢轴,并且在其他任何地方都没有使用。
    $items =
    $this->where( 'active', 1 )
         ->where( function ($query) {

              $query->whereIn( 'slug', $this->shared_slugs )
                    ->orWhere(function ($query) {

                        $query->whereRaw( $this->threshold_rank.' <= '.$this->user_rank )
                              ->whereIn('id', function ($query) {

                                  $query->select('admin_item_id')->from('f_user_access')->where('user_id', $this->user_id)->get();
                              });
                     })
                     ->orWhere(function ($query) {

                        $query->whereRaw( $this->threshold_rank.' > '.$this->user_rank )
                              ->where( 'rank', '>=', $this->user_rank );
                     });
         })->orderBy( 'order', 'ASC' )->get();

我喜欢第二个的原因是我可以将$shared_slugs作为一个数组传递,而不必先将其转换为字符串。但除此之外,我真的讨厌这种写法,例如where(function($query){})等等...另外,传递给该函数的$ids,在where.functions中无法访问,所以我必须先在类中定义它们。
第一个我喜欢因为有命名绑定且不那么难读,变量也是可以访问的...缺点是我必须调用这个函数将共享slug转换为一个数组。
不使用Eloquent和QueryBuilder真的很糟糕吗?至少在某些情况下...你们会怎么做才能使第二个示例更好呢?=/
更新:由于回答和反馈,我放弃了原始SQL。当前函数中有5个范围,并且一个(小)模型用于user_access。
    $items =
    $this->active() //Only active items AND... 1, 2 or 3

        ->where( function ($query) {

            $query->shared_slug()             //  1

            ->orWhere(function ($query) {      // OR  2
                $query->access_required()
                ->whereIn('id', UserAccess::get_access( $this->user_id ) );
            })

            ->orWhere(function ($query) {      // OR  3
                $query->no_access_required()
                ->whereRaw( 'rank >= '.$this->user_rank );
            });

        })->ASC()->get(); 

2
你可以使用作用域 https://laravel.com/docs/5.4/eloquent#query-scopes。你也可以使用 whereRaw() 代替 ->where(attribute, operator, value) - Kyslik
1
除非你正在创建“全局”范围,否则将它们保留在模型中,遵循文档并查看它们的命名方式、如何传递参数等。 - Kyslik
我现在有一些非常基本的作用域,我在多个模型上使用。是否有一个好的位置可以放置它们,以便所有模型都可以访问,但仍然必须调用?例如动态作用域ASC或作用域Active等。 - Maarten Kuijper
我不相信这是开箱即用的。但是你可以自己创建traits,比如OrderBy,并在其中拥有scopeDescscopeAsc - Kyslik
已经喜欢上它了,= / 在 Illuminate\Database\Eloquent\Model 中使用过的 trait。 - Maarten Kuijper
显示剩余2条评论
1个回答

5
使用查询构建器的主要好处是它将你与你选择的存储语言分离,例如MySQL、Oracle、SQLite等。如果你切换数据库类型,你可能需要大量重构原始SQL语句。相信我,当你开始一个项目并了解到这种情况时,情况并不美好。
然而,总会有例外情况,这正是Eloquent也具备使用原始语句的能力的原因。

嗯,我还没有考虑到这个...如果只是为了那个,我想我可以将第二个函数注释掉并将其保留在底部某处?或者我可以进一步优化它,并在其中加入一些注释,因为它不是一个字符串。 - Maarten Kuijper

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接