Laravel validation unique规则如何实现忽略大小写的唯一性校验
问题原因
你当前代码的核心问题是\Str::lower('name')仅对字符串'name'本身做小写转换,没有作用到数据库name字段的实际存储值,所以大小写比对逻辑完全没有生效。
修正方案
方案1:调整现有查询逻辑
需要用数据库原生方法对字段值做小写转换,引入DB门面处理即可:
首先在文件顶部引入依赖:
use Illuminate\Support\Facades\DB; use Illuminate\Support\Str;
调整查询代码:
// 不需要多余的orderBy,只要判断是否存在即可 $exists = Category::where(DB::raw('LOWER(name)'), '=', Str::lower(request('name')))->first(); if ($exists) { return redirect()->route('categories.index')->with('error', 'Nama kategori sudah ada'); } else { Category::create(request()->all()); }
方案2:使用Laravel验证规则实现(更符合框架最佳实践)
可以直接在请求验证阶段就完成大小写不敏感的唯一性校验,不需要手动写存在判断:
use Illuminate\Validation\Rule; use Illuminate\Support\Facades\DB; use Illuminate\Support\Str; // 验证逻辑放在控制器最前面 $request->validate([ 'name' => [ 'required', 'string', 'max:255', Rule::unique('categories')->where(function ($query) use ($request) { return $query->where(DB::raw('LOWER(name)'), Str::lower($request->input('name'))); }) ] ], [ 'name.unique' => 'Nama kategori sudah ada' ]); // 验证通过后直接创建即可 Category::create(request()->all()); return redirect()->route('categories.index')->with('success', 'Kategori berhasil ditambahkan');
额外优化建议(可选)
如果你的分类表数据量较大,上述查询会因为用到LOWER(name)函数无法命中普通索引,查询效率较低。可以在数据库层面新增小写生成列加唯一索引,同时实现性能优化和数据库级别的强校验:
-- MySQL 示例 ALTER TABLE categories ADD COLUMN name_lower VARCHAR(255) GENERATED ALWAYS AS (LOWER(name)) STORED, ADD UNIQUE INDEX uk_name_lower (name_lower);
加了这个索引之后,查询可以直接改成:
$exists = Category::where('name_lower', '=', Str::lower(request('name')))->first();
就算代码层面遗漏校验,数据库也会直接抛出唯一冲突错误,避免脏数据写入。
内容的提问来源于stack exchange,提问作者Rizal ihwan
相关产品推荐
相关产品推荐

