Mac*_*ski 5 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 no end date, because it's derived in controcc and rederived here.
public bool Deleted { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
创建它的代码也很简单:
using (var context = _factory.CreateDbContext(null))
{
var term = new AcademicTermDate();
term.StartDate = new DateTime(2001, month, 1);
context.AcademicTermDate.Add(term);
context.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)
有趣的是,如果我按照以下代码使用旧的普通 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);
}
Run Code Online (Sandbox Code Playgroud)
它按预期工作;在 context.SaveChanges() 上,我可以看到要填充的 RowVersion。
但是,如果我使用 InMemory 数据库提供程序(它似乎很适合用于我的测试),我可以看到不同的行为:RowVersion 仍然填充有 null 值(即根本没有初始化)。
对于后者,工厂定义为:
public MyContext CreateDbContext(string[] args)
{
var builder = new DbContextOptionsBuilder<MyContext>();
builder.UseInMemoryDatabase(databaseName: "InMemory");
return new MyContext(builder.Options);
}
Run Code Online (Sandbox Code Playgroud)
我是否缺少应提供的 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>
Run Code Online (Sandbox Code Playgroud)
非常感谢任何帮助。
有关测试的文档在期望管理InMemory方面做了认真的尝试。例如:
(InMemory) 并不是为了模仿关系数据库而设计的。
除其他外,这意味着
InMemory 允许您在关系数据库中保存违反引用完整性约束的数据。
如果您对模型中的属性使用 DefaultValueSql(string),则这是一个关系数据库 API,并且在针对 InMemory 运行时不会产生任何效果。
毫无疑问,初始化和更新 RowVersion 列值可以添加到此列表中。
然后他们给出提示:
对于许多测试目的来说,这些差异并不重要。但是,如果您想针对行为更像真正关系数据库的内容进行测试,请考虑使用 SQLite 内存模式。
就其价值而言,我同意第一部分,即:在您知道差异并不重要的情况下进行测试。如果您只想将数据库层用作随后在业务逻辑单元测试中使用的模拟数据的快速提供者,那么使用 InMemory 可能会很方便。
但我完全不同意第二个建议,即使用 SQLite 来测试更多依赖于正确数据层行为的函数。好吧,如果 SQLite 是生产数据库,那就继续吧。否则:始终针对与生产数据库相同的数据库品牌进行集成测试。数据库品牌和查询提供程序(将表达式转换为 SQL 的部分)之间存在太多差异,无法使集成测试足够可靠。如果 SQLite 不支持您自己的数据库品牌/查询提供商所支持的 LINQ 构造或语句或功能,该怎么办?避免它们来取悦 SQLite?我不这么认为。
所以我的建议是建立一个Sql Server集成测试数据库来测试RowVersion相关的代码。