带有 EF Core 和内存数据库提供程序的原始 sql

Posted

技术标签:

【中文标题】带有 EF Core 和内存数据库提供程序的原始 sql【英文标题】:Raw sql with EF Core and in-memory db provider 【发布时间】:2018-02-15 08:42:23 【问题描述】:

我的一个 API 路由使用原始 sql merge into 命令来执行原子 upsert 操作,在我的自动化测试中,我有一个使用内存数据库提供程序的 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 个上下文都指向同一个真实数据库,我们只是在代码中为不同的域(表集)设置了单独的上下文。 【参考方案1】:

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

【讨论】:

是的,我有一种感觉,只是想确定一下。我们最终只是通过单元测试来解决这个问题并手动验证实际查询,这足以满足我们的需求。 @ErikEJ 你知道情况是否仍然如此吗?我正在尝试使用内存数据库上下文对FromSql 进行测试并遇到了这个问题。那里有一些嘲笑 FromSql 和 DbQuery/DbSet 的人的样本,我只是认为这不是一个好方法。 是的,这里没有任何变化 如果您在 linux 上运行 ci/cd,那么祝您使用 localdb 好运。不支持。一场经典的 M$ 灾难。那我们用什么? SQL Express 应该符合要求【参考方案2】:

正如您发现的那样,内存中的提供程序不能进行关系操作(一个合理的限制)。

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

【讨论】:

【参考方案3】:

您可以使用 SQLite 代替 InMemory DB,它与 sql 配合得很好,而且设置起来非常简单,就像在内存数据库中一样。

https://docs.microsoft.com/en-us/ef/core/miscellaneous/testing/sqlite

【讨论】:

如果你打算走这条路,你不妨得到一个 Docker 容器并运行你将要使用的实际 RDBMS。不像 SQL 提供者都是可以互换的

以上是关于带有 EF Core 和内存数据库提供程序的原始 sql的主要内容,如果未能解决你的问题,请参考以下文章

带有 .NET EF Core 的内存缓存抛出错误

带有 EF Core 和 CosmosDB .NET 5 的 ASP.Net Core - IdentityRole 问题

EF Core:一统SQL和NoSQL数据库

带有 EF Core 更新实体的 ASP.Net 核心 Web Api 如何

带有 UWP 的 EF Core - Visual Studio 19

如何使用 ef core 对具有原始表名和属性的数据库进行反向工程