Entity framework core 使用Microsoft.EntityFrameworkCore.InMemory测试并发令牌
作为EF 6.1到EF Core 2.0迁移的一部分,我添加了一个简单的测试来检查并发令牌是否以同样的方式工作。但我注意到,这取决于底层数据库提供程序:它适用于SqlServer,但不适用于MS InMemory数据库 实体类非常简单:Entity framework core 使用Microsoft.EntityFrameworkCore.InMemory测试并发令牌,entity-framework-core,Entity Framework Core,作为EF 6.1到EF Core 2.0迁移的一部分,我添加了一个简单的测试来检查并发令牌是否以同样的方式工作。但我注意到,这取决于底层数据库提供程序:它适用于SqlServer,但不适用于MS InMemory数据库 实体类非常简单: public class AcademicTermDate { public int AcademicTermDateID { get; set; } public DateTime StartDate { get; set; } //but
public class AcademicTermDate
{
public int AcademicTermDateID { get; set; }
public DateTime StartDate { get; set; } //but no end date, because it's derived in controcc and rederived here.
public bool Deleted { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; }
}
创建它的代码也很简单:
using (var context = _factory.CreateDbContext(null))
{
var term = new AcademicTermDate();
term.StartDate = new DateTime(2001, month, 1);
context.AcademicTermDate.Add(term);
context.SaveChanges();
}
有趣的是,如果按照以下代码使用旧的普通Sql Server:
public MyContext CreateDbContext(string[] args)
{
var builder = new DbContextOptionsBuilder<MyContext>();
var connectionString = "server=.\\sql2012;Database=CA15;Trusted_Connection=True;";
builder.UseSqlServer(connectionString);
return new MyContext(builder.Options);
}
public MyContext CreateDbContext(字符串[]args)
{
var builder=new DbContextOptionsBuilder();
var connectionString=“服务器=。\\sql2012;数据库=CA15;可信连接=True;”;
使用SQLServer(connectionString);
返回新的MyContext(builder.Options);
}
它按预期工作;在context.SaveChanges()上,我可以看到要填充的行版本
但是,如果我使用InMemory数据库提供程序(这似乎很容易用于我的测试),我可以看到一种不同的行为:RowVersion仍然填充有null值(即根本没有初始化)
对于后者,工厂定义为:
public MyContext CreateDbContext(string[] args)
{
var builder = new DbContextOptionsBuilder<MyContext>();
builder.UseInMemoryDatabase(databaseName: "InMemory");
return new MyContext(builder.Options);
}
public MyContext CreateDbContext(字符串[]args)
{
var builder=new DbContextOptionsBuilder();
builder.UseInMemoryDatabase(数据库名:“InMemory”);
返回新的MyContext(builder.Options);
}
我是否缺少应提供的InMemory db的任何重要设置?这种差异似乎很奇怪,老实说,相当令人不安
所有代码目标.NET Core 2.0:
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.ComponentModel.Annotations" Version="4.4.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="2.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.0" />
</ItemGroup>
Exe
netcoreapp2.0
非常感谢您的帮助。使用InMemory进行测试时,请认真尝试期望管理。例如:
(InMemory)不是为了模仿关系数据库而设计的
除其他外,这意味着
-
InMemory将允许您在关系数据库中保存违反引用完整性约束的数据
-
如果对模型中的属性使用DefaultValueSql(字符串),则这是一个关系数据库API,在运行InMemory时不会产生任何影响
毫无疑问,可以将初始化和更新RowVersion列值添加到此列表中
然后他们给出提示:
对于许多测试目的,这些差异并不重要。但是,如果您想测试一些更像真实关系数据库的东西,那么在内存模式中考虑使用SQLite。
无论如何,我同意第一部分的观点,即:在你知道差异无关紧要的地方进行测试。如果您只想将数据库层用作模拟数据的快速提供者,则可以方便地使用InMemory,然后在业务逻辑单元测试中使用模拟数据
但我完全不同意第二条建议,即使用SQLite测试更依赖于正确数据层行为的函数。好吧,如果SQLite是生产数据库,那就继续吧。否则:始终针对与生产数据库相同的数据库品牌进行集成测试。数据库品牌和查询提供程序(将表达式转换为SQL的部分)之间存在太多差异,使得集成测试足够可靠。如果SQLite不支持您自己的数据库品牌/查询提供者所支持的LINQ构造、语句或特性,该怎么办?为了取悦SQLite而避免使用它们?我不这么认为
因此,我的建议是设置一个Sql Server集成测试数据库来测试与行版本相关的代码。内存数据库不会生成时间戳。然而,实体框架仍然验证时间戳是否与任何更新匹配
它们始终匹配,因为保持null
因此,您仍然可以通过为更新设置行版本来测试是否抛出了DbUpdateConcurrencyException
entity.Timestamp=新字节[]{1};
更新(实体);
等待上下文。SaveAsync();// EF Core 5.0及更低版本不支持与内存中提供程序进行并发检查,但这是计划中的。看
提供EF核心内存中数据库提供程序的包装器。具体解决以下EF错误
InMemory:Improve in memory key generation您是否尝试过使用fluent api设置并发令牌?是的,我尝试过:modelBuilder.Entity().Property(p=>p.RowVersion).valueGeneratedAndorUpdate().IsConcurrencyToken();好的,前面的代码可能不正确,但这段代码也不起作用:modelBuilder.Entity().Property(p=>p.RowVersion).valueGenerateAndorUpdate().IsRowVersion();让我恼火的是,原来的代码在Sql Server上运行得很好,但在InMemory db上却不行。所以我猜这个问题首先是关于数据库提供程序的。记住内存数据库和sql server实例上的数据库是不同的数据库,您检查过内存数据库中的行吗?回答得很好,谢谢。这可能是因为我的假设是错误的,因为我预期内存中的RDBMS会像其他任何RDBMS一样运行;看起来差异更为根本。缺少已实现/缺少的特性列表确实会有帮助,但我很不幸找到了。SQLite在这方面要好得多:。我可以理解你的观点,这可能被认为是一个集成测试;然而,从我的角度来看(我更倾向于db),时间戳没有得到正确维护是一个bug,而不是一个特性。我不认为EF团队同意你的观点。bug是指没有按预期运行的东西。我很确定他们不会声称在InMemory中支持RowVersions。(不要告诉任何人,但我看不到InMemory有多大的实际用途,因为无论我的DAL在哪里参与自动化测试,我都想100%确保它的行为与真实情况完全一致。我认为这是理所当然的