如何在Linq查询的选择列表中抽象字段?

Sha*_*ica 7 c# linq linq-to-entities entity-framework-5

我有一个特定的计算字段,我经常想在Linq查询的"选择"字段中返回,例如今年的客户订单总数,以及客户的其他人口统计信息.

public class Customer {
  public decimal TotalPurchasesThisYear(MyDataContext db) {
    return db.Orders.Where(o => o.CustomerID == ID)
                    .Sum(o => o.OrderTotalAmt);
  }
}

public class SomeReport {
  public void GetCustomerInfoBySalesperson(long salespersonID) {
    using (var db = new MyDataContext()) {
      var q = db.Customers.Where(c => c.SalespersonID == salespersonID)
                          .Select(c => new { c.Name, c.Address, ThisYearPurchases = c.TotalPurchasesThisYear(db) })
                          .ToList();
      // etc..
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

显然,这不起作用,因为TotalPurchasesThisYear没有SQL翻译.但其中的所有内容都有SQL翻译.我不想直接在查询中包含该代码,因为我在很多地方进行相同的计算.我的直觉告诉我这应该用a来完成,Expression但是我已经玩过了,并且无法找到正确的语法.

帮忙,有人吗?谢谢!

Sha*_*ica 0

好的,我找到了一种方法来做到这一点,尽管我不确定这是最好的方法:

public class CustomerOrderInfo {
  public long CustomerID;
  public decimal TotalPurchases;
}

public class Customer {
  public static Expression<Func<Customer, CustomerOrderInfo>> GetCustomerOrderInfo() {
    return c => new CustomerOrderInfo {
                  CustomerID = c.ID,
                  TotalPurchases = c.Orders.Where(o => o.OrderDate.Year == DateTime.Now.Year)
                                    .Sum(o => o.OrderTotalAmt)
                };
  }
}

public class SomeReport {
  public void GetCustomerInfoBySalesperson(long salespersonID) {
    using (var db = new MyDataContext()) {
      var q = db.Customers
                .Join(db.Customers.Select(Customer.GetCustomerOrderInfo()),
                      c => c.ID, i => i.CustomerID,
                      (c, i) => new { c.Name, c.Address, i.TotalPurchases })
                .ToList();
  // etc..
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

它可以工作......但是底层 SQL 最终以嵌套查询的联接结束,这不是我的理想。我希望看到底层 SQL 是简单的,例如:

select c.Name, c.Address, sum(o.OrderTotalAmt) TotalPurchases
from Customer c 
left join [Order] o on o.CustomerID = c.ID
where Year(o.OrderDate) = @year
group by c.Name, c.Address
Run Code Online (Sandbox Code Playgroud)