我希望能够在Entity Framework Core 2.0查询中重用我选择的lambda表达式的片段。

例如:

var result = await ctx.Customers
  .Select(cust => new CustomerDto {
    CustomerId = cust.Id,
    CustomerName = cust.Name,
    CurrentValue = cust.Orders
      .Where(order => order.OrderDate >= DateTime.Now.AddDays(-30)
      .Sum(order => order.TotalValue)
    })
    .ToListAsync();


由于我可能想在其他查询中计算CurrentValue属性(实际上,子查询比这更复杂),因此理想情况下,我希望将上述代码重构为以下形式:

var result = await ctx.Customers
  .Select(cust => new CustomerDto {
    CustomerId = cust.Id,
    CustomerName = cust.Name,
    CurrentValue = CalculateCustomerCurrentValueExpr(cust)
  })
  .ToListAsync();


我已经使用Linq.Expression创建了Linq谓词,但无法找到将Expression用作select语句元素的方法。

任何帮助将非常感激。

更新-使用.AsExpandable()/。Invoke()的性能

对于任何有兴趣的人,我运行了十次测试代码,均得出以下结果:

Standard Inline Code: 17ms (58,609 ticks)With .AsExpandable() and inline code 16ms (58,029 ticks)With .AsExpandable() and .Invoke() 16ms (58,224 ticks)

我怀疑如果运行了更多的测试周期,那么所有这三种情况的平均处理时间都将是相同的-至少达到我可以测量的准确度(简单StopWatch())。

感谢所有贡献者,特别是解决方案的SergeyA和Ivan Stoev的.AsExpandable()的简单解释

最佳答案

您可以重复使用LinqKit liblary(http://www.albahari.com/nutshell/linqkit.aspx)中具有AsExpandable扩展名的表达式。

例:

Expression<Func<Customer,long>> func = c => c.Orders
  .Where(order => order.OrderDate >= DateTime.Now.AddDays(-30)
  .Sum(order => order.TotalValue);

var result = await ctx.Customers
  .AsExpandable() // this allow to unwrap injected expression
  .Select(cust => new CustomerDto {
    CustomerId = cust.Id,
    CustomerName = cust.Name,
    CurrentValue = func.Invoke(cust) // this inject predefined expression
  })
  .ToListAsync();

07-28 06:24