使用EF Core SQLite添加记录时的自增主键冲突问题
问题场景
使用Microsoft.EntityFrameworkCore.Sqlite 7.0.8,数据库表定义如下:
CREATE TABLE Product ( name TEXT, price NUMERIC, quantity NUMERIC, productId INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL );
逆向工程生成实体后,手动将Price和Quantity改为decimal?类型:
public string? Name { get; set; } public decimal? Price { get; set; } public decimal? Quantity { get; set; } public long ProductId { get; set; }
插入新记录时未设置ProductId(依赖数据库自增),触发错误:
System.InvalidOperationException: The instance of entity type 'Product' cannot be tracked because another instance with the same key value for {'ProductId'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached
问题根源
SQL Server的自增主键(IDENTITY)会让EF Core自动识别该值由数据库生成,不会把类型默认值(如int/long的0)当作有效主键。但SQLite中,若EF Core未被明确告知ProductId是数据库生成值,会将long类型的默认值0当作要插入的主键值——如果数据库中已有ProductId=0的记录,就会出现实体跟踪冲突。
解决步骤
1. 显式配置主键为数据库生成
有两种方式可以让EF Core知道ProductId由数据库自动生成:
- 数据注解方式:在
ProductId属性上添加注解:
using System.ComponentModel.DataAnnotations.Schema; public string? Name { get; set; } public decimal? Price { get; set; } public decimal? Quantity { get; set; } [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public long ProductId { get; set; }
- Fluent API方式:在DbContext的
OnModelCreating方法中配置:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Product>() .Property(p => p.ProductId) .ValueGeneratedOnAdd(); }
配置完成后,EF Core会在插入新实体时忽略ProductId的默认值0,由SQLite的AUTOINCREMENT机制自动分配主键值,不会再触发跟踪冲突。
2. 逆向工程后的补充配置(关键)
使用Scaffold-DbContext逆向生成实体时,EF Core可能无法正确识别SQLite的AUTOINCREMENT属性,导致没有自动添加上述配置,所以必须手动补充。
额外说明
SQLite的INTEGER PRIMARY KEY AUTOINCREMENT是普通自增主键的增强版,它保证主键不会重用已删除的记录ID。如果不需要这个特性,用INTEGER PRIMARY KEY即可,EF Core的配置方式完全一致。
内容的提问来源于stack exchange,提问作者MrD at KookerellaLtd

