如何在Lumen Model中声明复合主键?解决find()调用报错问题
解决Lumen模型复合主键使用find()报错的问题
这个报错的原因很明确:Eloquent模型默认是为单主键设计的,当你把$primaryKey设置成数组(复合主键)时,底层的一些内部方法(比如mb_strpos)会期望接收字符串类型的主键名称,但拿到的却是数组,所以直接抛出了参数类型错误。
下面给你几个可行的解决方案:
方案一:直接使用where条件查询(最简单)
既然原生find()不支持复合主键,咱们直接用多条件where来实现同样的效果:
// 替换成你的实际参数值 $skTime = '20240520'; $skRegion = 'CN'; $skDevice = 'mobile'; $visit = Visit::where('sk_time', $skTime) ->where('sk_region', $skRegion) ->where('sk_device', $skDevice) ->first();
这个方法最直接,不需要修改模型代码,适合偶尔使用的场景。
方案二:在模型中自定义复合主键查询方法
如果需要多次使用复合主键查询,建议在模型里封装一个自定义方法,复用性更好:
// 在Visit模型中添加这个方法 public static function findByComposite($skTime, $skRegion, $skDevice) { return self::where('sk_time', $skTime) ->where('sk_region', $skRegion) ->where('sk_device', $skDevice) ->first(); } // 使用的时候就像调用原生方法一样方便 $visit = Visit::findByComposite('20240520', 'CN', 'mobile');
方案三:重写模型的find()方法(模拟原生调用体验)
如果你特别想保留find()的调用方式,可以重写模型的find()方法,让它支持数组形式的复合主键参数:
首先修改模型的$primaryKey为静态属性(因为静态方法里无法访问非静态属性):
namespace App; use Illuminate\Database\Eloquent\Model; class Visit extends Model { protected $table = 'ft_visit'; // 改成静态属性,方便静态方法访问 protected static $primaryKey = ['sk_time', 'sk_region', 'sk_device']; protected $fillable = [ 'sk_time', 'sk_region', 'sk_device', 'ds_page', ]; public $timestamps = false; public function time() { return $this->belongsTo(Time::class, 'sk_time'); } // 重写find方法 public static function find($keys, $columns = ['*']) { // 如果传入的不是数组,调用原生find方法处理单主键场景 if (!is_array($keys)) { return parent::find($keys, $columns); } // 校验主键数量是否匹配 if (count($keys) !== count(static::$primaryKey)) { throw new \InvalidArgumentException('传入的键数量必须与复合主键数量一致'); } $query = static::query(); // 绑定每个主键对应的查询条件 foreach (array_combine(static::$primaryKey, $keys) as $key => $value) { $query->where($key, $value); } return $query->first($columns); } }
这样你就可以像原生find()一样传入数组来查询复合主键了:
$visit = Visit::find(['20240520', 'CN', 'mobile']);
额外提醒
除了find(),Eloquent中依赖单主键的方法(比如findOrFail()、destroy())也会遇到同样的问题,如果需要使用这些方法,也需要按照类似的逻辑重写。
内容的提问来源于stack exchange,提问作者Vitor Grenzel
相关产品推荐
相关产品推荐

