我写了一段代码,在运行时构建一个EF Core Where()
predicate 。我以前从未这样做过,但出于需求,我不得不这样做。
要求只是在CreatedOn
或UpdatedOn
的7天内从数据库获取数据。
重构之前的版本是在循环中调用数据库7次,这存在性能问题。
当前实现按预期工作并返回预期结果。
这是当前代码:
private async Task SevenDaysCashOutFloor(DateTimeOffset today, IQueryable<BillPaymentVoucher> pastBillPayments, IQueryable<JournalVoucherPaymentVoucher> pastJournalVoucherPayments, CancellationToken token)
{
Expression<Func<BillPaymentVoucher, bool>> predicate = null!;
Expression<Func<BillPaymentVoucher, bool>> aggregatedPredicate = null!;
BinaryExpression binaryExpression = null!;
var param = Expression.Parameter(typeof(BillPaymentVoucher));
today = DateTimeOffset.UtcNow;
for (int days = 0; days < 7; days++)
{
var date = today.AddDays(-days);
predicate = (entity) => (
(entity.UpdatedOn.HasValue && entity.UpdatedOn.Value.Date == date.Date) ||
(entity.UpdatedOn.HasValue == false && entity.CreatedOn.Date == date.Date)
);
binaryExpression = Expression.OrElse(ExpressionReplacer.GetBody(aggregatedPredicate ?? predicate, param),
ExpressionReplacer.GetBody(predicate, param));
aggregatedPredicate = Expression.Lambda<Func<BillPaymentVoucher, bool>>(binaryExpression, param);
}
var finalPredicate = Expression.Lambda<Func<BillPaymentVoucher, bool>>(binaryExpression, param);
pastBillPayments = pastBillPayments.Where(finalPredicate);
}
我在运行时构建for
循环中Where()
所需的 predicate 。
一切都如预期的那样,但我想知道:
1.这是不是正确的写法
1.我应该使用复杂的Expression Tree
吗?
1.有没有一个简单的方法可以做到这一点?
1.这个代码可以被重构吗?
我以前从未使用过表达式树。
1条答案
按热度按时间ie3xauqp1#
Where
总是在运行时构造的。也不需要显式地检查空值。表达式将被转换成显式支持NULL值的SQL。此方法搜索
UpdatedOn
或CreatedOn
在某个日期范围内的行。您可以通过创建这些日期的列表并使用Contains
来替换它:这将产生:
虽然有些数据库(例如SQL Server)可以将
cast(UpdatedOn as date) = ...
转换为可以使用索引的范围搜索,但它们不能使用索引统计信息。更好的查询是显式搜索日期范围:
这消除了任何强制转换,从而允许服务器同时使用索引和统计信息