背景
我試圖通過將一些代碼提取到一些擴展方法中來清理我的代碼,如下所示。我偶然發現了具有該功能的LINQKitExpandable。我創建了一個簡單的擴展方法AtPointInTime,它將 aDateTimeOffset作為輸入(參見下面的代碼),但我一直收到錯誤訊息。我做錯了什么(在檔案中找不到解決方案)?
執行
[Expandable(nameof(AtPointInTimeImpl))]
public static IQueryable<TSource> AtPointInTime<TSource>(this IQueryable<TSource> query, DateTimeOffset pointInTime) where TSource : class, IBitemporal
{
return query.AsExpandable().Where(entity => AtPointInTimeFilter<TSource>().Invoke(entity, pointInTime));
}
private static Expression<Func<IQueryable<TSource>, DateTimeOffset, IQueryable<TSource>>> AtPointInTimeImpl<TSource>() where TSource : class, IBitemporal
{
return (query, pointInTime) => query.Where(entity => AtPointInTimeFilter<TSource>().Expand().Invoke(entity, pointInTime));
}
private static Expression<Func<TSource, DateTimeOffset, bool>> AtPointInTimeFilter<TSource>() where TSource : class, IBitemporal
{
return (entity, pointInTime) => entity.ValidTimeFrom <= pointInTime && (entity.ValidTimeTo > pointInTime || entity.ValidTimeTo == null);
}
用法
為了在我使用的特定時間點獲取所有公司AtPointInTime (注意:雙時態存盤解決方案)。
該
AtPointInTime還可以在一個子查詢,因此我伸出我叫AtPointInTime用Expandable。
示例#1
var companies = await _dbContext.Companies.AtPointInTime(DateTimeOffset.UtcNow).ToList()
示例#2
var query = from alarm in _dbContext.Alarms.AtPointInTime(request.PointInTime)
select new GetAlarmQueryResult
{
Alarm = alarm,
Company = _dbContext.Companies.AtPointInTime(alarm.Created).SingleOrDefault(),
};
錯誤
The LINQ expression 'DbSet<Company>
.Where(c => (entity, pointInTime) => (DateTimeOffset)entity.ValidTimeFrom <= pointInTime && (Nullable<DateTimeOffset>)entity.ValidTimeTo > (Nullable<DateTimeOffset>)pointInTime || entity.ValidTimeTo == null
.Invoke(
expr: c,
arg1: __pointInTime_0))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
uj5u.com熱心網友回復:
需要消除的幾件事:
這個表達:
return (entity, pointInTime) => entity.ValidTimeFrom <= pointInTime && (entity.ValidTimeTo > pointInTime || entity.ValidTimeTo == null);
應該是:
return (entity, pointInTime) => entity.ValidTimeFrom <= pointInTime && (entity.ValidTimeTo == null || entity.ValidTimeTo > pointInTime);
反過來說,它會在空檢查之前在比較中評估可空屬性。EF 可能能夠生成它,但可能不會。
我使用AsExpandable它的地方一直在DbSet,而不是IQueryable。嘗試將 AsExpandable 移出擴展方法并呼叫:
var companies = await _dbContext.Companies
.AsExpandable()
.AtPointInTime(DateTimeOffset.UtcNow)
.ToListAsync()
如果可行,則可能需要更新擴展方法以針對DbSet<TEntity>而不是IQueryable<TEntity>. 我懷疑它_dbContext.Companies.AsQueryable().AtPointInTime(...)會起作用,盡管它可能值得一試?:)
除此之外,它看起來應該適用于包裝時間檢查。如果我不得不冒險猜測擴展中的 AsExpandable() 呼叫而不是直接在 DbSet 上呼叫意味著AsExpandable沒有在運算式構建器中“采用”,或者反轉條件可能會按原樣傳遞并阻塞一代。
我假設普通的舊手動 linq 運算式作業正常?
var pointInTime = DateTimeOffset.UtcNow;
var companies = await _dbContext.Companies
.Where(entity => entity.ValidTimeFrom <= pointInTime
&& (entity.ValidTimeTo == null
|| entity.ValidTimeTo > pointInTime)
.ToListAsync();
uj5u.com熱心網友回復:
嘗試以下實作:
[Expandable(nameof(AtPointInTimeImpl))]
public static IQueryable<TSource> AtPointInTime<TSource>(this IQueryable<TSource> query, DateTimeOffset pointInTime)
where TSource : class, IBitemporal
{
return query.AsExpandable().Where(entity => entity.AtPointInTime(pointInTime));
}
private static Expression<Func<IQueryable<TSource>, DateTimeOffset, IQueryable<TSource>>> AtPointInTimeImpl<TSource>()
where TSource : class, IBitemporal
{
return (query, pointInTime) => query.Where(entity => entity.AtPointInTime(entity, pointInTime));
}
[Expandable(nameof(AtPointInTimeEntityImpl))]
public static bool AtPointInTime<TSource>(this TSource entity, DateTimeOffset pointInTime)
where TSource : class, IBitemporal
{
throw new NotImplementedException();
}
private static Expression<Func<TSource, DateTimeOffset, bool>> AtPointInTimeEntityImpl<TSource>()
where TSource : class, IBitemporal
{
return (entity, pointInTime) => entity.ValidTimeFrom <= pointInTime && (entity.ValidTimeTo > pointInTime || entity.ValidTimeTo == null);
}
AsExpandable如果您配置 EF Core 選項,也可以消除:
builder
.UseSqlServer(connectionString)
.WithExpressionExpanding(); // enabling LINQKit extension
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/363367.html
上一篇:如何在物體框架中的兩個表之間執行左連接操作時從左表中選擇唯一行
下一篇:Linq查詢選擇新的串列
