升级Entity Framework至6.0.12后Sqlite集成测试报错求助
EF从2.2.6升级至6.0.12后,内存Sqlite集成测试计算列函数报错问题解决
问题背景
将Entity Framework版本从2.2.6升级至6.0.12后,大量依赖内存Sqlite数据库的集成测试失败。问题与迁移中新增的数据库函数有关——该函数被用于DbContext的OnModelCreating()方法中定义计算列。
测试初始化执行以下代码:
_dbContext.Database.EnsureDeleted(); _dbContext.Database.EnsureCreated();
调用EnsureCreated()时抛出异常:
Microsoft.Data.Sqlite.SqliteException : SQLite Error 1: 'near "(": syntax error'
通过堆栈追踪定位到,异常触发于OnModelCreating()中的这段代码:
modelBuilder.Entity<MyObject>() .Property(p => p.LinkId) .HasComputedColumnSql("Schema.fn_link_id([Id])");
推测异常原因是EnsureCreated()不会执行迁移,导致数据库中不存在目标函数。
已尝试的无效方案
- 用
.Migrate()替代.EnsureCreated():由于Sqlite迁移存在列修改等限制,此方案失效;手动重写5年多的适配迁移成本过高,暂不考虑。 - 使用
.Migrate()并切换至本地SqlServer实例:本地测试可通过,但会增加CI/CD管道的额外开销与复杂度,不愿采用。 - 在测试中直接创建函数绕过迁移需求:仍出现相同语法错误,代码示例:
var connection = new SqliteConnection("DataSource=:memory:"); connection.Open(); connection.CreateFunction("Schema.fn_link_id", (int Id) => Guid.NewGuid()); var options = new DbContextOptionsBuilder<MyDbContext>() .UseSqlite(connection) .Options;
可行解决方案
问题核心在于Sqlite不支持SQL Server风格的架构(Schema)前缀,且CreateFunction方法无法带架构名注册函数。需做两处修改:
1. 注册Sqlite函数时去掉架构前缀
Sqlite没有SQL Server的架构概念,注册函数时直接使用fn_link_id作为函数名:
var connection = new SqliteConnection("DataSource=:memory:"); connection.Open(); // 移除Schema前缀,仅注册函数名 connection.CreateFunction("fn_link_id", (int Id) => Guid.NewGuid().ToString()); var options = new DbContextOptionsBuilder<MyDbContext>() .UseSqlite(connection) .Options;
2. 动态调整计算列的SQL语句
在OnModelCreating()中,根据当前数据库类型动态修改计算列的函数调用语句,适配Sqlite与其他数据库(如SQL Server)的语法差异:
protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<MyObject>() .Property(p => p.LinkId) .HasComputedColumnSql(provider => provider == "Microsoft.EntityFrameworkCore.Sqlite" ? "fn_link_id([Id])" : "Schema.fn_link_id([Id])" ); }
这样修改后,内存Sqlite测试时会正确调用注册的函数,同时不影响生产环境中SQL Server的原有逻辑。
内容的提问来源于stack exchange,提问作者Justiciar
相关产品推荐
相关产品推荐

