【发布时间】:2023-01-18 18:06:55
【问题描述】:
我写了一段代码,它在运行时构建了一个 EF Core Where() 谓词。我以前从未这样做过,但出于要求我不得不这样做。
要求只是在 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);
}
我正在运行时构建谓词,Where() 在 for 循环中需要它。
一切都按预期工作,但我想知道:
-
这是否是正确的写法?
-
我应该使用复杂的
Expression Tree吗? -
有没有一种简单的方法可以实现这一目标?
-
这段代码可以重构吗?
我以前从未使用过表达式树。
【问题讨论】:
-
如果您的代码有效,它可能不属于 SO。您应该尝试将其发布到Code Review
-
您知道您在谓词中不仅限于
==和!=,不是吗?您不需要进行 7 次单独比较来确定过去 7 天内是否发生了什么,只需使用>=。 -
@Damien_The_Unbeliever,随着时间的推移,7 可能会发生变化,它已经发生了几次变化
-
但是,整个事情仍然应该像
var notBefore = DateTimeOffset.UtcNow.AddDays(-7).Date; pastBillPayments = pastBillPayments.Where(e=>e.UpdateOn.HasValue && e.UpdateOn.Value >= notBefore || e.CreatedOn >= notBefore);,除非你的数据包括未来的日期,在这种情况下它会稍微复杂一些,但不是你正在构建的。 -
Where总是在运行时构造。没理由用entity.UpdatedOn.HasValue && entity.UpdatedOn.Value.Date,用entity.UpdatedOn?.Date == date.Date就够了。这将被转换为 SQL,例如cast(UpdatedOn as date) ==@d1。实际情况应该是entity.UpdatedOn?.Date == date.Date || entity.CreatedOn?.Date == date.Date。整个表达式循环可以替换为与多个值进行比较的单个表达式。甚至listOfDates.Contains(entity.UpdatedOn) || listOfDates.Contains(entity.CreatedOn)
标签: c# linq lambda entity-framework-core expression-trees