简体   繁体   English

使用 Linq2Sql 的临时表

[英]Temporal tables with Linq2Sql

I've got a generic repository to either get en entity by ID or to get all entities:我有一个通用存储库,可以通过 ID 获取实体或获取所有实体:

    internal class Repository<TEntity> : IRepository<TEntity>
        where TEntity : BaseEntity
    {
        protected SaiContext Context { get; }

        /// <summary>Gets the entity set.</summary>
        protected virtual DbSet<TEntity> Set => Context.Set<TEntity>();

        public Repository(SaiContext context)
        {
            Context = context;
        }

        public async Task<TEntity> GetAsync(int entityId, IEnumerable<string> includeProperties = null)
        {
            try
            {
                return await GetQueryableWithIncludes(includeProperties).SingleAsync(entity => entity.Id == entityId);
            }
            catch (InvalidOperationException)
            {
                throw new EntityNotFoundException(typeof(TEntity), entityId);
            }
        }

        public async Task<IEnumerable<TEntity>> GetAllAsync(IEnumerable<string> includeProperties = null)
        {
            return await GetQueryableWithIncludes(includeProperties).ToListAsync();
        }

        protected IQueryable<TEntity> GetQueryableWithIncludes(IEnumerable<string> includeProperties = null)
        {
            IQueryable<TEntity> queryable = Set;

            if (includeProperties == null)
            {
                return queryable;
            }

            foreach (var propertyName in includeProperties)
            {
                queryable = queryable.Include(propertyName);
            }

            return queryable;
        }
    }

After having configured the DbContext for entity relations, navigation properties along with all the rest is being loaded correctly for all entities.在为实体关系配置 DbContext 后,导航属性以及所有 rest 正在为所有实体正确加载。

Now I've been asked to use temporal SQL tables so that all entities have a validity range.现在我被要求使用临时 SQL 表,以便所有实体都有一个有效范围。

With SQL I'd include FOR SYSTEM_TIME AS OF @validityDate in the query.使用 SQL 我会在查询中包含FOR SYSTEM_TIME AS OF @validityDate

What is the easiest way (if there is any) to adapt the existing implementation in order to respect @validityDate ?调整现有实现以尊重@validityDate的最简单方法(如果有的话)是什么?

What I've tried:我试过的:

  1. Look for a way to configure the wanted system time when performing the SQL query.在执行 SQL 查询时,寻找一种配置所需系统时间的方法。 ISSUE: I couldn't find a way.问题:我找不到方法。
  2. Expose the query through a table valued function allowing to pass @validityDate as a parameter.通过值 function 的表公开查询,允许将@validityDate作为参数传递。 ISSUE: I can't pass the parameter using Linq2Sql (or at least I didn't figurte out how).问题:我无法使用 Linq2Sql 传递参数(或者至少我没有弄清楚如何)。
  3. Create a table valued function performing the joins (instead of letting EF do them) so it can be called with context.FromSqlRaw(<query>) .创建一个表值 function 执行连接(而不是让 EF 执行连接),以便可以使用context.FromSqlRaw(<query>)调用它。 ISSUE: How to create the c# object tree? ISSUE: 如何创建 c# object 树? (multiple rows are being returned as there are 1 to many relations) (由于存在一对多的关系,因此返回了多行)

All examples using temporal tables I've found use FromSqlRaw .我发现使用时态表的所有示例都使用FromSqlRaw If possible I'd like to avoid it, as it means that the entire DB context sonfiguration becomes useless and additional code for the mappings has to be included.如果可能的话,我想避免它,因为这意味着整个数据库上下文配置变得无用,并且必须包含映射的附加代码。

I've found the solution with the efcore-temporal-query ( nuget ) library.我找到了efcore-temporal-query ( nuget ) 库的解决方案。

The code has been adapted to use temporal tables as described in the README .该代码已被改编为使用README中描述的临时表。

The repository methods now accept an optional parameter validityDate:存储库方法现在接受可选参数有效性日期:

    public async Task<TEntity> GetAsync(int entityId, DateTime? validityDate = null, IEnumerable<string> includeProperties = null)
    {
        try
        {
            var query = GetQueryableWithIncludes(includeProperties);
            query = GetQueryableWithValidityDate(query, validityDate);
            return await query.SingleAsync(entity => entity.Id == entityId);
        }
        catch (InvalidOperationException)
        {
            throw new EntityNotFoundException(typeof(TEntity), entityId);
        }
    }

    protected IQueryable<TEntity> GetQueryableWithIncludes(IEnumerable<string> includeProperties = null)
    {
        IQueryable<TEntity> queryable = Set;

        if (includeProperties == null)
        {
            return queryable;
        }

        foreach (var propertyName in includeProperties)
        {
            queryable = queryable.Include(propertyName);
        }

        return queryable;
    }

    private static IQueryable<TEntity> GetQueryableWithValidityDate(IQueryable<TEntity> query, DateTime? validityDate)
    {
        return validityDate.HasValue ? query.AsOf(validityDate.Value) : query;
    }

Where te relevant part for the historized query is query.AsOf(validityDate.Value) .历史查询的相关部分是query.AsOf(validityDate.Value)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM