使用EF Core和内存数据库提供程序的原始SQL

18

我的一个API路由使用了原始的SQL merge into 命令来执行原子插入操作。在我的自动化测试中,我有一个TestServer实例,它使用内存数据库提供程序。但是会出现错误,可能是因为内存提供程序不支持运行原始SQL命令 - 这是真的吗?如果不是,该如何使其正常工作呢?

这是测试的Startup类:

// In memory DB for testing
services.AddDbContext<MyContext>(optionsBuilder => optionsBuilder.UseInMemoryDatabase("stuff"));
services.AddDbContext<MyStatusContext>(optionsBuilder => optionsBuilder.UseInMemoryDatabase("status"));
services.AddDbContext<MyUserRolesContext>(optionsBuilder => optionsBuilder.UseInMemoryDatabase("userroles"));

而API代码如你所预期:

var count = await context.Database.ExecuteSqlCommandAsync(@"merge into ...", default(CancellationToken), ...);
return count;

这段代码在生产环境中对真实数据库可以正常工作,但我无法在测试中使用内存提供程序使其正常工作。还有希望吗?自定义 SQL 脚本的通常测试策略是什么?


值得注意的是,这3个上下文都指向同一个真实数据库,我们只是在代码中为不同的域(表集)拥有单独的上下文。 - gzak
3个回答

20

由于InMemory提供程序是NoSQL非关系型提供程序,因此您没有希望。您应该使用SQL Server(例如localdb)进行集成测试。


1
是的,我有这种感觉,只是想确认一下。我们最终只是通过单元测试来覆盖它,并手动验证实际查询,这对我们的需求来说是一个足够的权衡。 - gzak
@ErikEJ 你知道这是否仍然是事实吗?我正在尝试使用内存数据库上下文进行FromSql测试,但遇到了这个问题。有些人在模拟FromSqlDbQuery/DbSet,但我认为那不是一个好的方法。 - akousmata
是的,在这里没有任何变化。 - ErikEJ
如果你在Linux上运行CI/CD,那么使用LocalDB就祝你好运了。它不被支持,这是一个经典的微软灾难。那么我们该用什么呢? - jenson-button-event
SQL Express 应该能够满足需求。 - ErikEJ

5

正如您所发现的,内存提供程序无法执行关系操作(这是一个合理的限制)。

我曾遇到类似的问题,最终编写了一个库来扩展内存提供程序以支持关系操作 - EntityFrameworkCore.Testing。它可以执行 ExecuteSqlCommand/ExecuteSqlCommandAsync 的模拟操作。


0
在这种情况下,你可以选择使用SQLite作为内存数据库来运行测试套件,以避免使用网络。它支持许多SQL功能,但也有一些限制。
services.AddDbContext<YourContext>(options =>
                options.UseSqlite(connection)
            );

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接