
laravel 中使用 eloquent 模型查询返回空结果,而 db::table() 却能正常获取数据,通常是因为模型启用了软删除(softdeletes),导致已“删除”的记录被自动排除,而原生查询不受影响。
laravel 中使用 eloquent 模型查询返回空结果,而 db::table() 却能正常获取数据,通常是因为模型启用了软删除(softdeletes),导致已“删除”的记录被自动排除,而原生查询不受影响。
在 Laravel 开发中,你可能会遇到这样一种看似“诡异”的现象:对同一张表执行完全相同的条件查询(如 whereIn(‘attendance_date_id’, [925, 926])),使用 DB::table(‘attendances’) 能查出多条记录,而使用 Attendance::class 模型却始终返回空集合:
Route::get('v1/testapi', function (Request $request) { return [ 'withDB' => DB::table('attendances') ->select("id", "attendance_date_id", "remarks") ->whereIn('attendance_date_id', [925, 926]) ->get(), 'withModel' => Attendance::select("id", "attendance_date_id", "remarks") ->whereIn('attendance_date_id', [925, 926]) ->get() ]; });
输出显示 withDB 包含 5 条有效数据,而 withModel 为空数组 —— 这并非 bug,而是 Laravel Eloquent 的默认行为设计。
根本原因:SoftDeletes 特性自动过滤
当你在 Attendance 模型中引入了 use SoftDeletes; 并定义了 $dates = [‘deleted_at’];(或 Laravel 9+ 中的 $casts = [‘deleted_at’ => ‘datetime’];),Eloquent 会自动为所有常规查询添加隐式约束:
WHERE deleted_at IS NULL
这意味着:即使数据库中存在 attendance_date_id IN (925, 926) 的记录,只要其 deleted_at 字段非 NULL(即已被“软删除”),Eloquent 就会将其静默排除,不返回给调用方。
而 DB::table() 是底层查询构建器,不感知模型逻辑,也不应用任何全局作用域(Global Scopes),因此它忠实地返回所有匹配的物理行——包括软删除的数据。
验证与调试方法
你可以快速验证是否存在软删除记录:
// 查看是否启用了 SoftDeletes dd(class_uses(Attendance::class)); // 应包含 IlluminateDatabaseEloquentSoftDeletes // 手动查询软删除数据(绕过默认过滤) $softDeleted = Attendance::withTrashed() ->select("id", "attendance_date_id", "remarks", "deleted_at") ->whereIn('attendance_date_id', [925, 926]) ->get(); // 仅查已被软删除的记录 $onlyTrashed = Attendance::onlyTrashed() ->whereIn('attendance_date_id', [925, 926]) ->get();
若 withTrashed() 返回了预期数据,即可确认问题根源。
正确处理建议
- ✅ 日常查询:保持默认行为(安全、符合业务逻辑),避免误展示已归档/删除的数据;
- ✅ 需要恢复或管理时:显式调用 withTrashed() 或 onlyTrashed();
- ⚠️ 慎用 withoutGlobalScopes():它会禁用所有全局作用域(包括软删除、租户隔离等),可能引发权限或数据一致性风险;
- ? 不要移除 SoftDeletes 仅为了“让查询有结果”——这违背软删除的设计初衷,应通过业务逻辑而非绕过机制来解决。
小结
| 对比维度 | DB::table() | Eloquent Model |
|---|---|---|
| 是否感知软删除 | 否 | 是(自动添加 WHERE deleted_at IS NULL) |
| 是否受全局作用域影响 | 否 | 是 |
| 适用场景 | 快速脚本、报表、迁移、调试 | 主业务逻辑、CRUD、需生命周期管理的场景 |
理解这一机制,不仅能快速定位类似“查询失灵”问题,更是掌握 Laravel 数据层抽象能力的关键一步。