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

Dapper.Contrib插入SQLite记录时id字段始终为NULL的问题

SQLite插入记录时首字段id始终为NULL问题排查

问题复现

尝试向SQLite数据表插入记录时,插入后表的首个id字段始终为NULL。
初始建表语句:

CREATE TABLE Tests(id INTEGER, nr INTEGER);

基于.NET 6.0编写的测试代码,使用Dapper.Contrib实现插入:

using Dapper.Contrib.Extensions;
using System.Data.SQLite;


namespace ConsoleApp48
{
    public class Program
    {
        static void Main(string[] args)
        {
            SQLiteConnection sqlite_conn;
            sqlite_conn = new SQLiteConnection("Data Source=database.db;Version=3;New=True;Compress=True; ");
            sqlite_conn.Open();

            Test t;
            t = new Test() { id = 1, nr = 1 };
            sqlite_conn.Insert<Test>(t);
            t = new Test() { id = 5, nr = 5 };
            sqlite_conn.Insert<Test>(t);

            sqlite_conn.Close();
        }
    }

    public class Test
    {
        public int id { get; set; }
        public int nr { get; set; }
    }
}

执行后查询数据库dump结果:

sqlite> .dump
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE Test(id INTEGER, nr INTEGER);
CREATE TABLE Tests(id INTEGER, nr INTEGER);
INSERT INTO Tests VALUES(NULL,1);
INSERT INTO Tests VALUES(NULL,5);
COMMIT;
sqlite>

数据库同时存在Test表为次要问题:最初误以为表名需要与类名完全一致,因此先创建了Test表,插入失败后又创建了结构相同的Tests表。
核心异常:插入的两条记录id字段均为NULL,手动赋值的1、5没有被写入。
项目依赖版本:

  • Dapper.Contrib: 2.0.78
  • System.Data.Sqlite.Core: 1.0.116

根本原因

Dapper.Contrib内置默认映射规则:

  • 自动将名称为Id/id的字段识别为自增主键,插入操作时会默认忽略手动给该字段赋的值,等待数据库生成自增主键值后回填
  • 默认将类名做复数化处理后作为映射表名,因此类名为Test时,框架实际操作的表是Tests,这也是数据库自动出现Tests表插入记录的原因

当前表结构中id字段没有配置主键约束、也没有声明自增属性,数据库不会自动生成id值,最终插入的字段值就为NULL。

修复方案

根据业务需求二选一即可:

  1. 遵循默认约定,将id设为自增主键
    修改建表语句:
    CREATE TABLE Tests(
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        nr INTEGER
    );
    
    该场景下不需要手动给id字段赋值,插入完成后框架会自动将数据库生成的自增ID回填到实体对象的id属性中。
  2. 需要手动指定id值时,显式标记主键类型
    给实体类的id字段添加[ExplicitKey]特性,告知Dapper.Contrib该字段为需要手动传值的主键,插入时不要忽略手动赋值:
    using Dapper.Contrib.Extensions;
    
    public class Test
    {
        [ExplicitKey]
        public int id { get; set; }
        public int nr { get; set; }
    }
    
    如果不需要表名自动复数化,可以给类添加[Table("Test")]特性,显式指定实体映射的表名,避免框架默认操作Tests表。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 16:33:40