You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Laravel模型查询中将软删除条件设为首个子句?

解决方案:调整软删除全局作用域的添加顺序

要让deleted_at IS NULL条件自动排在WHERE子句最前面,无需额外添加作用域,只需调整软删除全局作用域的添加时机即可:

在你的Company模型中重写boot方法,手动优先添加SoftDeletingScope:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Database\Query\Builder;

/**
 * @method static|Builder createdAtBigger(\DateTime $datetime)
 * @method static|Builder nameLike(string $name)
 * @method static|Builder oneOfBoard(array $boardIds)
 */
class Company extends Model
{
    use SoftDeletes;

    protected static function boot()
    {
        // 先添加软删除的全局作用域,确保它的条件最先被加到查询里
        static::addGlobalScope(new SoftDeletingScope);
        
        // 再执行父类和其他trait的初始化逻辑
        parent::boot();
    }

    // 你的现有作用域方法保持不变
    public function scopeCreatedAtBigger(Builder $builder, $datetime)
    {
        return $builder->where('created_at', '>', $datetime);
    }

    public function scopeNameLike(Builder $builder, $name)
    {
        return $builder->where('name', 'LIKE', '%'.$name.'%');
    }

    public function scopeOneOfBoard(Builder $builder, $boardIds)
    {
        return $builder->whereIn('board_id', $boardIds);
    }

    /**
     * the other methods and scopes
     * ...
     * ...
     * ...
     */
}

为什么这样有效?

Laravel的全局作用域是按添加顺序生成WHERE条件的:默认情况下SoftDeletes trait的初始化逻辑在模型自身boot方法之后执行,所以它的whereNull('deleted_at')会被追加到条件末尾。

现在我们把软删除作用域的添加放在模型boot方法最开头,让它成为第一个被应用的全局作用域,对应的条件自然就会排在WHERE子句的最前面。

效果验证

执行你原来的查询代码后,生成的SQL会变成:

SELECT * 
FROM company 
WHERE deleted_at IS NULL 
  AND name LIKE '%XX Company%' 
  AND created_at > '2022-02-14' 
  AND board_id IN (1,2,3,4);

数据库会先通过deleted_at的索引过滤掉绝大多数已删除的行,再执行后续的模糊查询和范围查询,直接提升查询效率。

这个改动不需要修改任何现有业务代码,所有调用Company模型的地方都会自动生效,完全满足你的需求。

内容的提问来源于stack exchange,提问作者biyro2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 07:01:57