Eloquent ORM中关于PrimaryKey配置

问题描述

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