ASP.NET Core+SQLite下EF Core种子数据忽略IsActive=0的问题排查
EF Core种子数据中IsActive=0被忽略,SQLite自动设为默认值1
使用ASP.NET Core和SQLite开发银行应用时,向数据库写入种子数据时发现IsActive = 0的设置被EF Core忽略,所有BankAccount实例的IsActive都被设为默认值1。查看生成的SQL日志,发现第二个账户的INSERT语句中完全省略了IsActive字段,导致数据库使用列的默认值。
种子数据代码
modelBuilder.Entity<BankAccount>().HasData( new BankAccount { PkAccountId = 1, FkAccountTypeId = 1, Balance = 1500.00M, IsActive = 1, DateOpened = DateTime.Parse("2024/03/09") }, new BankAccount { PkAccountId = 2, FkAccountTypeId = 2, Balance = 3000.00M, IsActive = 0, DateOpened = DateTime.Parse("2020/06/01") }, new BankAccount { PkAccountId = 3, FkAccountTypeId = 3, Balance = 8000.00M, IsActive = 1, DateOpened = DateTime.Parse("2021/01/01") }, new BankAccount { PkAccountId = 4, FkAccountTypeId = 4, Balance = 12000.00M, IsActive = 1, DateOpened = DateTime.Parse("2024/07/06") }, new BankAccount { PkAccountId = 5, FkAccountTypeId = 5, Balance = 4500.00M, IsActive = 1, DateOpened = DateTime.Parse("2020/03/08") });
生成的SQL日志
info: Microsoft.EntityFrameworkCore.Database.Command[20101] Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] INSERT INTO "Bank Account" ("PkAccountId", "Balance", "DateOpened", "FkAccountTypeId", "IsActive") VALUES (1, '1500.0', '2024-03-09 00:00:00', 1, 1); info: Microsoft.EntityFrameworkCore.Database.Command[20101] Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] INSERT INTO "Bank Account" ("PkAccountId", "Balance", "DateOpened", "FkAccountTypeId") VALUES (2, '3000.0', '2020-06-01 00:00:00', 2); info: Microsoft.EntityFrameworkCore.Database.Command[20101] Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] INSERT INTO "Bank Account" ("PkAccountId", "Balance", "DateOpened", "FkAccountTypeId", "IsActive") VALUES (3, '8000.0', '2021-01-01 00:00:00', 3, 1); INSERT INTO "Bank Account" ("PkAccountId", "Balance", "DateOpened", "FkAccountTypeId", "IsActive") VALUES (4, '12000.0', '2024-07-06 00:00:00', 4, 1); INSERT INTO "Bank Account" ("PkAccountId", "Balance", "DateOpened", "FkAccountTypeId", "IsActive") VALUES (5, '4500.0', '2020-03-08 00:00:00', 5, 1);
表创建配置代码
modelBuilder.Entity<BankAccount>(entity => { // Table Name entity.ToTable("Bank Account"); // Primary Key entity.HasKey(e => e.PkAccountId); entity.Property(e => e.PkAccountId).ValueGeneratedOnAdd(); // Properties entity.Property(e => e.DateOpened) .HasColumnType("TEXT") .HasDefaultValue(DateTime.Now) .IsRequired(); entity.Property(e => e.Balance) .HasColumnType("REAL") .IsRequired(); entity.Property(e => e.IsActive) .HasColumnType("INTEGER") .HasDefaultValue(1) .IsRequired(); // Foreign Key Relationship entity.HasOne(e => e.BankAccountType) .WithMany(e => e.BankAccounts) .HasForeignKey(e => e.FkAccountTypeId) .OnDelete(DeleteBehavior.Restrict); });
问题原因
核心原因是EF Core的HasData逻辑会忽略等于CLR默认值的属性:
IsActive是int类型,其CLR默认值为0- 当你在种子数据中设置
IsActive = 0时,EF Core会认为你没有显式赋值(因为值等于CLR默认值),因此生成INSERT语句时会省略该列 - 由于表配置中给
IsActive设置了HasDefaultValue(1),SQLite会自动使用这个默认值填充该列,最终导致第二个账户的IsActive被设为1
解决方案
方案1:将IsActive改为bool类型(推荐)
bool类型的CLR默认值是false,对应SQLite的0,显式设置false时EF Core会识别为主动赋值,不会忽略该列:
- 修改模型属性:
public bool IsActive { get; set; }
- 更新表配置:
entity.Property(e => e.IsActive) .HasColumnType("INTEGER") .HasDefaultValue(true) // 对应原来的默认值1 .IsRequired();
- 调整种子数据:
// 原来的IsActive=1改为true,IsActive=0改为false new BankAccount { PkAccountId = 2, FkAccountTypeId = 2, Balance = 3000.00M, IsActive = false, DateOpened = DateTime.Parse("2020/06/01") }
方案2:使用可空int类型(int?)
将IsActive改为可空int,其CLR默认值为null,显式设置0时EF Core会识别为主动赋值:
- 修改模型属性:
public int? IsActive { get; set; }
- 表配置可保留原设置(
HasDefaultValue(1)依然生效,当值为null时数据库用默认值) - 种子数据无需修改,保持
IsActive = 0即可
方案3:禁用EF Core的默认值忽略逻辑(不推荐)
通过配置强制EF Core包含所有属性,即使值等于CLR默认值,但这种方式可能影响其他属性的行为,需谨慎使用:
在表配置中添加:
entity.Property(e => e.IsActive) .HasColumnType("INTEGER") .HasDefaultValue(1) .IsRequired() .ValueGeneratedNever(); // 告诉EF该值不会由数据库生成,必须显式提供
注意:此方式会取消数据库的值生成逻辑,所有场景下都需要显式赋值IsActive,否则会报错。
内容的提问来源于stack exchange,提问作者Ryan Burns
相关产品推荐
相关产品推荐

