【问题标题】:Querying Data in a System-Versioned Temporal Table in Entity Framework Core在 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'

有没有办法在查询结束时自动追加这条语句?

就像截取查询并应用查询过滤器一样,就像一个软表,但现在它没有过滤,它只是语句末尾的语句。

【问题讨论】:

    标签: c# asp.net entity-framework .net-core aspnetboilerplate


    【解决方案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)

      【讨论】:

        猜你喜欢
        • 2020-09-02
        • 1970-01-01
        • 2021-10-20
        • 1970-01-01
        • 2021-06-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多