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

Sqlite内存模式下EnsureCreated()创建Northwind测试库异常问题

解决SQLite内存模式下EnsureCreated()抛出“表已存在”异常的问题

看起来你遇到的是EF Core在SQLite内存数据库环境下的模型构建或表创建逻辑冲突问题,结合你的描述(SQL Server正常、仅多表时触发、Region仅定义一次),下面是几个针对性的排查方向和解决方案:

1. 先排查模型是否存在重复表映射

虽然你确认Region只配置了一次,但有可能其他实体的映射不小心指向了Region表(比如复制粘贴代码时的疏忽)。可以在测试中添加代码,打印所有实体对应的表名,验证是否有重复:

// 在context.Database.EnsureCreated()之前添加
var model = context.Model;
foreach (var entityType in model.GetEntityTypes())
{
    Console.WriteLine($"实体: {entityType.ClrType.Name} -> 表名: {entityType.GetTableName()}");
}

如果输出中发现多个实体对应Region表,那就是问题根源,找到那个错误配置的实体修正即可。

2. 解决EF Core模型缓存导致的冲突

EF Core会默认缓存DbContext的模型,在测试场景下,如果多个测试方法共享了模型缓存,可能会出现旧模型的残留配置(比如之前测试中临时添加的表映射)。可以通过自定义模型缓存键工厂,强制每次测试生成全新的模型:

首先定义一个自定义的缓存键工厂:

public class UniqueTestModelCacheKeyFactory : IModelCacheKeyFactory
{
    public object Create(DbContext context)
    {
        // 每次返回全新的对象,避免复用缓存的模型
        return Guid.NewGuid();
    }
}

然后在测试的DbContext配置中替换服务:

var builder = new DbContextOptionsBuilder<NorthwindContext>()
    .UseSqlite(connection)
    .ReplaceService<IModelCacheKeyFactory, UniqueTestModelCacheKeyFactory>();

3. 调整SQLite内存数据库的使用方式

SQLite内存数据库的生命周期和连接绑定:只有当连接保持打开时,内存数据库才存在,而EnsureDeleted()在内存模式下的行为可能和你预期不符(因为删除表后,连接依然存在,后续操作可能触发奇怪的重建逻辑)。可以简化测试代码,利用using自动管理连接和上下文,去掉不必要的EnsureDeleted():

public async Task UpdateCategoryWithCorrectEtag(Category expectedCategory) {
    // 使用using自动释放连接
    using var connection = new SqliteConnection("DataSource=:memory:");
    connection.Open();
    
    var builder = new DbContextOptionsBuilder<NorthwindContext>()
        .UseSqlite(connection);
    
    // 使用using自动释放上下文
    using var context = new NorthwindContext(builder.Options);
    
    context.Database.EnsureCreated();
    var x = context.Categories.Count();
    
    // 无需手动调用EnsureDeleted或Close,using会自动处理
}

4. 排查实体关联导致的表创建顺序问题

如果你的实体之间有外键关联(比如其他表引用了Region),EF Core在SQLite下创建表的顺序可能触发重复创建表的bug。可以尝试手动创建表来验证:

// 替换context.Database.EnsureCreated()为手动执行SQL
await context.Database.ExecuteSqlRawAsync(@"
CREATE TABLE Region (
    RegionID INTEGER NOT NULL PRIMARY KEY,
    RegionDescription TEXT NOT NULL
);
-- 这里添加其他表的创建SQL,比如Categories表
CREATE TABLE Categories (
    CategoryID INTEGER NOT NULL PRIMARY KEY,
    CategoryName TEXT NOT NULL,
    Description TEXT,
    Picture BLOB
);
");

如果手动创建表没有报错,说明是EnsureCreated()的自动生成逻辑在SQLite下的问题,此时可以考虑使用EF Core迁移(context.Database.Migrate())代替EnsureCreated(),迁移的表创建逻辑更稳定。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:06:07