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。
修复方案
根据业务需求二选一即可:
- 遵循默认约定,将
id设为自增主键
修改建表语句:
该场景下不需要手动给CREATE TABLE Tests( id INTEGER PRIMARY KEY AUTOINCREMENT, nr INTEGER );id字段赋值,插入完成后框架会自动将数据库生成的自增ID回填到实体对象的id属性中。 - 需要手动指定
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
相关产品推荐
相关产品推荐

