c# - SQLite 内存数据库使用时态表测试 EF Core 应用程序
问题描述
我们在 Entity Framework Core 应用程序中使用系统版本化的时态表。这非常有效,但是我们在创建测试时遇到了问题。
我一直在按照本指南使用 SQLite 内存数据库来测试 Microsoft 的 EF Core 应用程序。
https://docs.microsoft.com/en-us/ef/core/testing/sqlite#using-sqlite-in-memory-databases
问题是它Sqlite
会抛出一个异常SysStartTime
。这是意料之中的,因为该属性被标记为prop.ValueGenerated = Microsoft.EntityFrameworkCore.Metadata.ValueGenerated.OnAddOrUpdate;
inDbContext
并且通常由 Sql Server 处理。无论如何可以在 SQLite 中完成这项工作吗?
SqliteException:SQLite 错误 19:'NOT NULL 约束失败:User.SysStartTime'。
用户:
public class User : IEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public DateTime SysStartTime { get; set; }
public DateTime SysEndTime { get; set; }
[Required]
public string ExternalId { get; set; }
}
xUnit测试:
public class QuestionUpdateTest: IDisposable
{
private readonly DbConnection _connection;
private readonly ApplicationDbContext _context = null;
public ChoiceSequencingQuestionUpdateTest()
{
var dbContextOptions = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseSqlite(CreateInMemoryDatabase())
.Options;
_connection = RelationalOptionsExtension.Extract(dbContextOptions).Connection;
_context = new ApplicationDbContext(dbContextOptions);
_context.User.Add(new User()
{
ExternalId = "1"
});
_context.SaveChangesNoUser();
}
private static DbConnection CreateInMemoryDatabase()
{
var connection = new SqliteConnection("Filename=:memory:");
connection.Open();
return connection;
}
public void Dispose() => _connection.Dispose();
[Fact]
public void Test2()
{
}
}
应用程序上下文:
public int SaveChangesNoUser()
{
//Wont help since the property is marked as ValueGenerated
foreach (var changedEntity in ChangeTracker.Entries())
{
if (changedEntity.Entity is IEntity entity)
{
switch (changedEntity.State)
{
case EntityState.Added:
entity.SysStartTime = DateTime.Now;
break;
}
}
}
return base.SaveChanges();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
foreach (var property in modelBuilder.Model.GetEntityTypes()
.SelectMany(t => t.GetProperties())
.Where(p => p.ClrType == typeof(string)))
{
if (property.GetMaxLength() == null)
property.SetMaxLength(256);
}
foreach (var property in modelBuilder.Model.GetEntityTypes()
.SelectMany(t => t.GetProperties())
.Where(p => p.ClrType == typeof(DateTime)))
{
property.SetColumnType("datetime2(0)");
}
foreach (var et in modelBuilder.Model.GetEntityTypes())
{
foreach (var prop in et.GetProperties())
{
if (prop.Name == "SysStartTime" || prop.Name == "SysEndTime")
{
prop.ValueGenerated = Microsoft.EntityFrameworkCore.Metadata.ValueGenerated.OnAddOrUpdate;
}
}
}
base.OnModelCreating(modelBuilder);
}
移民:
public partial class Temporaltablesforallentities : Migration
{
List<string> tablesToUpdate = new List<string>
{
"User",
};
protected override void Up(MigrationBuilder migrationBuilder)
{
foreach (var table in tablesToUpdate)
{
string alterStatement = $@"ALTER TABLE [{table}]
ADD PERIOD FOR SYSTEM_TIME ([SysStartTime], [SysEndTime])";
migrationBuilder.Sql(alterStatement);
alterStatement = $@"ALTER TABLE [{table}]
SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = History.[{table}], DATA_CONSISTENCY_CHECK = ON));";
migrationBuilder.Sql(alterStatement);
}
}
protected override void Down(MigrationBuilder migrationBuilder)
{
foreach (var table in tablesToUpdate)
{
string alterStatement = $@"ALTER TABLE [{table}] SET (SYSTEM_VERSIONING = OFF);";
migrationBuilder.Sql(alterStatement);
alterStatement = $@"ALTER TABLE [{table}] DROP PERIOD FOR SYSTEM_TIME";
migrationBuilder.Sql(alterStatement);
alterStatement = $@"DROP TABLE History.[{table}]";
migrationBuilder.Sql(alterStatement);
}
}
}
解决方案
像这样解决它protected override void OnModelCreating(ModelBuilder modelBuilder)
:
foreach (var et in modelBuilder.Model.GetEntityTypes())
{
foreach (var prop in et.GetProperties())
{
if (prop.Name == "SysStartTime" || prop.Name == "SysEndTime")
{
if (Database.IsSqlServer())
{
prop.ValueGenerated = Microsoft.EntityFrameworkCore.Metadata.ValueGenerated.OnAddOrUpdate;
}
else
{
prop.SetDefaultValue(DateTime.Now);
}
}
}
}
推荐阅读
- tailwind-css - 将实用程序类添加到正文标记
- python - 从 numpy 数组在 matplotlib 中实时绘图
- php - 登录后如何添加目的地?
- java - 为什么这个线程代码有时会打印错误的意外结果?
- docker - 适用于 Amazon Linux 2 AMI 的 ASP.NET Core 基础映像
- maven - Mule SDK Plugin 导致 java.lang.NoClassDefFoundError: org/json/JSONObject
- regex - 在 perl 中使用双重感叹匹配 cond
- javascript - 我正在使用 nodemailer,我需要向数组中的所有用户发送电子邮件?
- kotlin - `AnAction` 返回的 `FileSystemTree` 为 `null`
- c++ - 具有多个输出的内联汇编块