在LINQ中重用Lambda Select Fragments

时间:2018-02-01 17:14:19

标签: c# linq lambda entity-framework-core

我希望能够在我的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()/。调用()

的性能

对于任何感兴趣的人,我运行了十次测试代码,产生了以下结果:

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()的简单解释

2 个答案:

答案 0 :(得分:3)

您可以重复使用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(); 

答案 1 :(得分:0)

我将表达式存储在静态文件中,并重用我需要它们的表达式,以确保包含所有相关数据。也许这对你也有用

GetStore()中,我重用了一个名为 ClientAccess 的表达式,并将其传递给 ShopExpressions 中的表达式。

GetPage()使用简单的直接实现。

<强> ShopExpressions.cs

* * * * * cd /home/arifur/workspace_python/erpdatabasebackup && bash backup_database.sh

<强> Controller.cs

public static IQueryable<IStore> StoreLite(IQueryable<IStore> dbSet)
{
    var result = dbSet
        .Include(str => str.VATs)
            .ThenInclude(vat => vat.VAT)
                .ThenInclude(vat => vat.Culture)
                    .ThenInclude(cult => cult.Items)
                        .ThenInclude(itm => itm.Culture)
        .Include(str => str.Options)
            .ThenInclude(opt => opt.Items)
                .ThenInclude(itm => itm.Option)
        .Include(str => str.Cultures)
            .ThenInclude(cult => cult.Items)
                .ThenInclude(itm => itm.Culture)
                    .ThenInclude(cult => cult.Items)
                        .ThenInclude(itm => itm.Culture)
        .Include(str => str.Pages)
            .ThenInclude(page => page.Sections)
                .ThenInclude(section => section.Elements);

    return result;
}

public static IQueryable<IStore> Store(IQueryable<IStore> dbSet)
{
    var result = StoreLite(dbSet)
        .Include(str => str.Categorys)
            .ThenInclude(cat => cat.Products)
                .ThenInclude(prd => prd.InfoItems)
                    .ThenInclude(itm => itm.Culture)
                        .ThenInclude(cult => cult.Items)
                            .ThenInclude(itm => itm.Culture);

    return result;
}

public static IQueryable<IPage> Page(IQueryable<IPage> dbSet)
{
    var result = dbSet
        .Include(page => page.Sections)
            .ThenInclude(sec => sec.Elements)
        .Include(page => page.CSS)
        .Include(page => page.Script)
        .Include(page => page.Meta);

    return result;
}
相关问题