You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CodeIgniter 4种子器向NOT NULL列插入NULL值的PostgreSQL适配问题

CI4种子器PostgreSQL与MySQL的NOT NULL列行为差异问题解惑

问题场景

使用CodeIgniter 4(CI4)迁移生成的表,所有列默认都是NOT NULL。在MySQL中执行种子器时,仅插入部分列也能正常运行,未指定的列会被自动处理;但切换到PostgreSQL后,迁移仅需将DOUBLE改为NUMERIC即可正常执行,种子器却报错:

Message: pg_query(): Query failed: ERROR:  null value in column "created_at" violates not-null constraint

即使手动设置created_at和updated_at的填充规则,其他NOT NULL列仍会触发相同错误,而这些列在MySQL中会被留空处理。目前手动给缺失字段填充空值可正常执行,但需要明确问题原因,以及是否会影响后续表单提交等POST请求场景。

迁移代码示例

class Configuracoes extends Migration
{
    public function up()
    {
        $this->forge->addField([
            'id_config'       => [
                'type'           => 'INT',
                'constraint'     => 9,
                'usigned'        => true,
                'auto_increment' => true,
            ],

            'nome_do_app' => [
                'type'       => 'VARCHAR',
                'constraint' => 128
            ],

            'tema' => [
                'type' => 'INT'
            ],

            'xNome' => [
                'type'       => 'VARCHAR',
                'constraint' => 128
            ],

            'xFant' => [
                'type'       => 'VARCHAR',
                'constraint' => 128
            ],

            'CNPJ' => [
                'type'       => 'VARCHAR',
                'constraint' => 14
            ],

            'telefone' => [
                'type'       => 'VARCHAR',
                'constraint' => 11
            ],

            'endereco' => [
                'type'       => 'VARCHAR',
                'constraint' => 256
            ],

            'arquivo-imagem-de-fundo-login' => [
                'type'       => 'VARCHAR',
                'constraint' => 128
            ],

            'logomarca' => [
                'type'       => 'VARCHAR',
                'constraint' => 128
            ],

            'created_at' => [
                'type'   => 'DATETIME'
            ],

            'updated_at' => [
                'type'   => 'DATETIME'
            ],

            'deleted_at' => [
                'type'   => 'DATETIME'
            ]
        ]);

        $this->forge->addKey('id_config', true);
        $this->forge->createTable('configuracoes');
    }
}

种子器代码示例

$this->db->table('configuracoes')->insert([
    'nome_do_app' => 'App',
    'tema'        => '4',
    'xNome'       => 'name',
    'xFant'       => 'name',
    'CNPJ'        => '0000000000000',
    'telefone'    => '(000) 0000-0000',
    'endereco'    => 'adress'
]);

问题原因

核心是MySQL与PostgreSQL对NOT NULL列的默认值处理逻辑不同:

  • MySQL在宽松模式下,当列定义为NOT NULL但未指定默认值时,会自动生成隐式默认值:字符串类型默认是空串'',数字类型默认是0,datetime类型默认是'0000-00-00 00:00:00'(这是MySQL的非标准行为)。
  • PostgreSQL严格遵循SQL标准,NOT NULL列必须有明确的赋值,或者列定义时指定了显式默认值。如果插入时未指定该列的值,数据库会认为要插入NULL,直接触发NOT NULL约束错误。

你的迁移代码中,除了自增的id_config,所有列都是NOT NULL但未设置默认值,所以PostgreSQL插入未指定的列时就会报错,而MySQL会自动补全隐式默认值。

解决方案

  1. 迁移时设置显式默认值
    在迁移的字段定义中,给需要自动填充的列添加default参数:

    'created_at' => [
        'type'   => 'DATETIME',
        'default' => 'CURRENT_TIMESTAMP'
    ],
    'arquivo-imagem-de-fundo-login' => [
        'type'       => 'VARCHAR',
        'constraint' => 128,
        'default' => ''
    ],
    'tema' => [
        'type' => 'INT',
        'default' => 0
    ]
    

    对于软删除的deleted_at,可以设置为允许NULL:

    'deleted_at' => [
        'type'   => 'DATETIME',
        'null' => true
    ]
    
  2. 启用CI4模型自动时间戳
    创建对应的模型ConfiguracoesModel.php,开启自动时间戳功能,CI4会自动填充created_at和updated_at:

    class ConfiguracoesModel extends Model
    {
        protected $table = 'configuracoes';
        protected $primaryKey = 'id_config';
        protected $useTimestamps = true;
        protected $allowedFields = ['nome_do_app', 'tema', ...]; // 允许批量赋值的字段
    }
    

    之后用模型插入数据,无需手动处理时间戳:

    $model = model(ConfiguracoesModel::class);
    $model->insert([
        'nome_do_app' => 'App',
        'tema'        => '4',
        // 其他字段...
    ]);
    
  3. 种子器中指定所有NOT NULL列的值
    如果不想修改迁移,就在种子器中明确写出所有NOT NULL列的取值,比如空串、0或者合适的默认值。

对POST请求场景的影响

会直接影响POST请求。如果前端表单未提交某些NOT NULL且无默认值的字段,PostgreSQL会和种子器场景一样触发约束错误。

解决思路和种子器一致:

  • 前端确保所有必填字段都有值(比如做表单校验);
  • 后端接收请求时,给缺失的字段设置默认值;
  • 数据库层面给列添加显式默认值。

内容的提问来源于stack exchange,提问作者Nathan Rodrigues

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 21:55:24