使用 Linq2Sql 的时态表
Temporal tables with Linq2Sql
我有一个通用存储库,可以通过 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;
}
}
为实体关系配置 DbContext 后,所有实体的导航属性以及所有其他属性都正确加载。
现在我被要求使用 temporal SQL tables 以便所有实体都有一个有效范围。
使用 SQL 我会在查询中包含 FOR SYSTEM_TIME AS OF @validityDate
。
为了尊重 @validityDate
,调整现有实施的最简单方法(如果有的话)是什么?
我尝试过的:
- 寻找一种在执行 SQL 查询时配置所需系统时间的方法。问题:我找不到方法。
- 通过 table 值函数公开查询,允许将
@validityDate
作为参数传递。问题:我无法使用 Linq2Sql 传递参数(或者至少我不知道如何传递)。
- 创建一个执行连接的 table 值函数(而不是让 EF 执行连接),以便可以使用
context.FromSqlRaw(<query>)
调用它。问题:如何创建 C# 对象树? (返回多行,因为存在一对多关系)
我发现所有使用时间 tables 的示例都使用 FromSqlRaw
。如果可能的话,我想避免它,因为这意味着整个数据库上下文配置变得无用,并且必须包含用于映射的附加代码。
我在 efcore-temporal-query (nuget) 库中找到了解决方案。
代码已调整为使用 README 中所述的临时表。
存储库方法现在接受可选参数 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;
}
历史查询的相关部分是 query.AsOf(validityDate.Value)
。
我有一个通用存储库,可以通过 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;
}
}
为实体关系配置 DbContext 后,所有实体的导航属性以及所有其他属性都正确加载。
现在我被要求使用 temporal SQL tables 以便所有实体都有一个有效范围。
使用 SQL 我会在查询中包含 FOR SYSTEM_TIME AS OF @validityDate
。
为了尊重 @validityDate
,调整现有实施的最简单方法(如果有的话)是什么?
我尝试过的:
- 寻找一种在执行 SQL 查询时配置所需系统时间的方法。问题:我找不到方法。
- 通过 table 值函数公开查询,允许将
@validityDate
作为参数传递。问题:我无法使用 Linq2Sql 传递参数(或者至少我不知道如何传递)。 - 创建一个执行连接的 table 值函数(而不是让 EF 执行连接),以便可以使用
context.FromSqlRaw(<query>)
调用它。问题:如何创建 C# 对象树? (返回多行,因为存在一对多关系)
我发现所有使用时间 tables 的示例都使用 FromSqlRaw
。如果可能的话,我想避免它,因为这意味着整个数据库上下文配置变得无用,并且必须包含用于映射的附加代码。
我在 efcore-temporal-query (nuget) 库中找到了解决方案。
代码已调整为使用 README 中所述的临时表。
存储库方法现在接受可选参数 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;
}
历史查询的相关部分是 query.AsOf(validityDate.Value)
。