问题描述
业务中遇到主键不是自增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。