问题描述
我已经基于Microsoft sql文档创建了时态表使用默认历史记录表创建时态表。
迁移:
public partial class Temporaltables : Migration
{
List<string> tablesToUpdate = new List<string>
{
"Images","Languages","Questions","Texts","Medias",};
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.sql($"CREATE SCHEMA History");
foreach (var table in tablesToUpdate)
{
string alterStatement = $@"ALTER TABLE [{table}] ADD SysstartTime datetime2(0) GENERATED ALWAYS AS ROW START HIDDEN
CONSTRAINT DF_{table}_Sysstart DEFAULT GETDATE(),SysEndTime datetime2(0) GENERATED ALWAYS AS ROW END HIDDEN
CONSTRAINT DF_{table}_SysEnd DEFAULT CONVERT(datetime2 (0),'9999-12-31 23:59:59'),PERIOD FOR SYstem_TIME (SysstartTime,SysEndTime)";
migrationBuilder.sql(alterStatement);
alterStatement = $@"ALTER TABLE [{table}] SET (SYstem_VERSIONING = ON (HISTORY_TABLE = History.[{table}]));";
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 = $@"ALTER TABLE [{table}] DROP DF_{table}_Sysstart,DF_{table}_SysEnd";
migrationBuilder.sql(alterStatement);
alterStatement = $@"ALTER TABLE [{table}] DROP COLUMN SysstartTime,COLUMN SysEndTime";
migrationBuilder.sql(alterStatement);
alterStatement = $@"DROP TABLE History.[{table}]";
migrationBuilder.sql(alterStatement);
}
migrationBuilder.sql($"DROP SCHEMA History");
}
}
关于如何建立时态表的完整示例:
https://stackoverflow.com/a/64244548/3850405
这确实很好,但是现在我想访问SysstartTime
的值。
我尝试过的事情:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime SysstartTime { get; set; }
ApplicationDbContext.cs:
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")
{
prop.ValueGenerated = Microsoft.EntityFrameworkCore.Metadata.ValueGenerated.OnAddOrUpdate;
}
}
}
和
modelBuilder.Entity<Question>(e =>
{
e.Property(p => p.SysstartTime).ValueGeneratedOnAddOrUpdate();
});
每次迁移都会导致以下结果:
migrationBuilder.AddColumn<DateTime>(
name: "SysstartTime",table: "Questions",type: "datetime2(0)",nullable: false,defaultValue: new DateTime(1,1,DateTimeKind.Unspecified));
这当然会导致以下Update-Database
命令的错误:
每个表中的列名必须唯一。中的列名“ SysstartTime” 表“”已多次指定。
我一直在阅读这两个问题,并且似乎已经在Entity Framework Core 2.2中运行:
Net Core: Entity Framework and SQL Server Temporal Tables,Automatic Scaffolding
Entity Framework Core and SQL Server 2016 temporal tables
试图禁用“隐藏”功能,但没有帮助
sql:
ALTER TABLE [dbo].Questions ALTER COLUMN SysstartTime DROP HIDDEN;
解决方法
对于已经具有列的表,我只是为迁移删除了var ans = File.ReadLines(@"Engines\" + url_engine_code)
.SkipWhile(s => !s.TrimStart().StartsWith("[REG]")) // find line with [REG]
.Skip(1) // skip line with [REG]
.TakeWhile(s => !s.TrimStart().StartsWith("[LAP]"))
.Where(s => s.Trim() != String.Empty)
.ToList();
var ans2 = File.ReadLines(@"Engines\" + url_engine_code)
.SkipWhile(s => !s.TrimStart().StartsWith("[LAP]")) // find line with [LAP]
.Skip(1) // skip line with [LAP]
.Where(s => s.Trim() != String.Empty)
.ToList();
和Up
值,然后它起作用了:
Down
由于我以后不想编辑迁移生成的默认代码,因此决定对新实体执行以下操作:
通常向迁移添加migrationBuilder.AddColumn<DateTime>(
name: "SysStartTime",table: "Questions",type: "datetime2(0)",nullable: false,defaultValue: new DateTime(1,1,DateTimeKind.Unspecified));
值:
DateTime
ApplicationDbContext.cs:
public DateTime SysStartTime { get; set; }
public DateTime SysEndTime { get; set; }
迁移,如果您已经有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")
{
prop.ValueGenerated = Microsoft.EntityFrameworkCore.Metadata.ValueGenerated.OnAddOrUpdate;
}
}
}
,请删除这些行:
Schema History
在GitHub上的讨论: