在 Entity Framework Core 中查询系统版本时态表中的数据
Posted
技术标签:
【中文标题】在 Entity Framework Core 中查询系统版本时态表中的数据【英文标题】:Querying Data in a System-Versioned Temporal Table in Entity Framework Core 【发布时间】:2019-11-09 06:02:27 【问题描述】:我们正在实施一种查询临时表的解决方案。
当在 SQL Server 上为任何表启用临时表时,SQL 将自动在表的末尾添加第二个带有额外“_History”的表以跟踪历史记录。例如,如果我们有一个“student”表,SQL server 将添加“student_History”表。
要查询学生历史,我们只需要查询学生表并在语句末尾添加FOR SYSTEM_TIME AS OF '2015-09-01 T10:00:00.7230011';
。
所以不要写:
Select * from student
我们会写:
Select * from student FOR SYSTEM_TIME AS OF '2015-09-01 T10:00:00.7230011'
有没有办法在查询结束时自动追加这条语句?
就像截取查询并应用查询过滤器一样,就像一个软表,但现在它没有过滤,它只是语句末尾的语句。
【问题讨论】:
【参考方案1】:它可以通过扩展方法来完成,我找到了一段可以帮助你的代码:
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Migrations;
using System;
using System.Linq;
namespace core
public static class Extensions
public static void AddTemporalTableSupport(this MigrationBuilder builder, string tableName, string historyTableSchema)
builder.Sql($@"ALTER TABLE tableName ADD
SysStartTime datetime2(0) GENERATED ALWAYS AS ROW START HIDDEN NOT NULL,
SysEndTime datetime2(0) GENERATED ALWAYS AS ROW END HIDDEN NOT NULL,
PERIOD FOR SYSTEM_TIME (SysStartTime, SysEndTime);");
builder.Sql($@"ALTER TABLE tableName SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = historyTableSchema.tableName ));");
public static DbContext GetDbContext<T>(this DbSet<T> dbSet) where T : class
var infrastructure = dbSet as IInfrastructure<IServiceProvider>;
return (infrastructure.Instance.GetService(typeof(ICurrentDbContext)) as ICurrentDbContext).Context;
public static string GetTableName<T>(this DbSet<T> dbSet) where T : class
var entityType = dbSet.GetDbContext().Model.GetEntityTypes().FirstOrDefault(t => t.ClrType == typeof(T))
?? throw new ApplicationException($"Entity type typeof(T).Name not found in current database context!");
var tableNameAnnotation = entityType.GetAnnotation("Relational:TableName");
return tableNameAnnotation.Value.ToString();
public static IQueryable<T> ForSysTime<T>(this DbSet<T> dbSet, DateTime time) where T : class
return dbSet.FromSql($"SELECT * FROM dbo.[dbSet.GetTableName()] FOR SYSTEM_TIME AS OF 0", time.ToUniversalTime());
用法:
var date = DateTime.Parse("2018-08-28 16:30:00");
var students = ctx.student.ForSysTime(date);
这个扩展方法是Mirek写的,你可以找到完整的文章here。
【讨论】:
嗨,此扩展方法是否适用于 wheres 和 groupsby,以及其他语法适用于 EF Linq? 能否与linq中的其他查询结合使用? 它假定你的架构名称是 dbo!【参考方案2】:Entity Framework Core (6) 最新版本支持时态表。
正如Microsoft devBlogs 中所述,EF Core 6.0 支持:
使用 EF Core 迁移创建临时表 再次使用迁移将现有表转换为临时表 从过去某个时间点恢复数据 查询历史数据查询历史数据可以看here
【讨论】:
【参考方案3】:你可以试试这个 nuget pacakge https://www.nuget.org/packages/EntityFrameworkCore.SqlServer.TemporalTable/
支持:
从 Linq 创建时间查询 临时表迁移。(使用 Add-Migration、Script-Migration)【讨论】:
以上是关于在 Entity Framework Core 中查询系统版本时态表中的数据的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Entity Framework Core 中运行存储过程?
如何在 Entity Framework Core 中运行存储过程?
什么是自有实体?何时以及为什么在 Entity Framework Core 中使用 Owned Entity?
Entity Framework Core 中 TimeSpan 的总和
Entity Framework优化一:引发了“System.Data.Entity.Core.EntityCommandExecutionException”类型的异常