问题描述
业务中遇到主键不是自增id字段,在Model中只配置了$primaryKey后,使用$model->create(...)
返回的Model,出现主键被设置成0的问题
为了更直接的找到问题原因,用Demo来演示,表结构如下:
CREATE TABLE `test` (
`pk_id` int(11) NOT NULL,
`data` int(11) NOT NULL DEFAULT '0',
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`pk_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ORM对应的Model类,只设置了$primaryKey = 'pk_id'
,代码如下:
使用Artisan调试代码,由$model->create([])
后获得的对象中,pk_id是0,输出如下:
直觉考虑,如果主键是id自增字段,那么Model创建后,会自动将数据库中自增的主键回写到Model对象中。 但是如果主键不需要自增,应该不需要有回写主键的操作。
调试代码
调试进入create()
方法中,这里有save()
操作
进入save()
方法中,发现有insert()
操作
继续进入performInsert()
方法,找到之前断言的setId
操作
当看到insertAndSetId()
之后,可以断定,回写主键是在这里执行的
在调用insertAndSetId()
方法的外部,有if ($this->getIncrementing()) {...}
判断,只需要让判断返回值是false就可以解决问题。
验证效果
在之前的Model类中,新增 $incrementing
属性,设置成false
再次使用$model->create()
获取对象,效果如下:
pk_id不再被覆盖成0
Eloquent/Model类中关于PrimaryKey的所有属性配置
<?php
abstract class Model
{
// ...
/**
* The primary key for the model.
*
* @var string
*/
protected $primaryKey = 'id';
/**
* The "type" of the auto-incrementing ID.
*
* @var string
*/
protected $keyType = 'int';
/**
* Indicates if the IDs are auto-incrementing.
*
* @var bool
*/
public $incrementing = true;
// ...
}
其中$primaryKey
和$incrementing
两个属性之前介绍过,剩下的$keyType
属性默认是int
,如果对主键id赋值成字符串$model->id = 'abc';
,toArray()
之后,id会被设置成(int) 'abc'
,也就是 0。