【问题标题】:LINQ to SQL Query Issue in Entity Framework实体框架中的 LINQ to SQL 查询问题
【发布时间】:2012-03-03 07:46:31
【问题描述】:

我的以下查询在 LINQ to SQL 中运行良好。现在我想把它改成Entity Framework

var _sale = from emp in setupEmployees
            join sales in vwSaleTargets on emp.EmployeeID equals sales.EmployeeID
            join price in vwPeriodPricings
               on new { sales.SKUID, sales.PeriodID } 
               equals new { SKUID = (int?)price.SKUID, PeriodID = (int?)price.PeriodID }
            join sk in setupSKUs on sales.SKUID equals sk.SKUID
            join br in setupBrands on sk.BrandID equals br.BrandID
            where emp.EmployeeID == 123 && sales.StartDate.Year == 2012 
            select new { emp, sales, price, sk, br };

var lstSale = _sale.ToList(); //to avoid n+1 queries in case of grouping
var sale2 = from x in lstSale
            group x by new { x.sk, x.emp } into grouping
            select new 
            {
                 EmployeeName = grouping.Key.emp.EmployeeName,
                 SKUID = grouping.Key.sk.SKUID,
                 SKUName = grouping.Key.sk.Title,
                 MonthSale =(double?)grouping
                          .Where(x => x.sales.StartDate.Month == 2 && 
                                      x.sales.StartDate.Year == 2012)
                          .Select(t=>t.sales.SalesQuantity)
                          .Sum(t=>t.Value)?? 0,
                 MonthSaleValue = (double?)grouping
                          .Where(x => x.sales.StartDate.Month == 2 && 
                                      x.sales.StartDate.Year == 2012)
                          .Sum(x => x.sales.SalesQuantity * x.price.ExFactoryPrice)  
                             ?? 0,
            };
Console.WriteLine(sale2.OrderBy(x => x.SKUName).ToList());

在实体框架中它给了我这样的结果

Name SKUID SKUName MonthSale MonthSaleValue 
EMP1  36    SKU1     113     61375.95 
EMP1  17    SKU2     113     6656.83 
EMP1  18    SKU3     113     9984.68 
EMP1  19    SKU4     113     15169.12 

在 L2S 中,我得到了这样的正确结果

Name SKUID SKUName MonthSale MonthSaleValue 
    EMP1  36    SKU1     74     40193.1 
    EMP1  17    SKU2     113     6656.83 
    EMP1  18    SKU3     461     40733.96
    EMP1  19    SKU4     2     268.48

问候

【问题讨论】:

  • 我已经编辑了很多格式 - 标签不能很好地与 Markdown 配合使用。
  • 谢谢!请看一下这个问题。我的主要问题是所有 sku 的月度销售重复
  • 我刚刚注意到 ToList() 部分 - 这意味着您应该能够看到 lstSale 中的差异,因为其余部分将在 LINQ to Objects 中完成。
  • 我正在制作列表以避免 N+1 查询。如果我删除 tolist() 查询需要很长时间才能执行
  • 这本身就很有趣。但我会尽量简化它,以便找出问题所在。

标签: c# linq entity-framework linq-to-sql entity-framework-4


【解决方案1】:

作为一种寻找答案的方法...

要按照@Jon Skeet 的建议进行诊断,您需要对其进行简化并查看您在 lstSale 中得到的结果,以便将 LINQ 与 SQL 与 EntityFramework 进行比较。

因此,以下几行可能会有所帮助(不一定在语法上正确,因为我没有检查所有源对象,但是我只是查看查询并将其简化为您可以看到的地方)

var _sale = from emp in setupEmployees
            join sales in vwSaleTargets on emp.EmployeeID equals sales.EmployeeID
            join price in vwPeriodPricings
               on new { sales.SKUID, sales.PeriodID } 
               equals new { SKUID = (int?)price.SKUID, PeriodID = (int?)price.PeriodID }
            join sk in setupSKUs on sales.SKUID equals sk.SKUID
            where emp.EmployeeID == 123 && sales.StartDate.Year == 2012 && sales.StartDate.Month == 2
            select new 
            { 
                EmployeeName = emp.EmployeeName, 
                StartDate = sales.StartDate,
                SalesQuantity = sales.SalesQuantity, 
                ExFactoryPrice = price.ExFactoryPrice, 
                SKUID = sk.SKUID,
                SKUName = sk.SKUName 
            };

var lstSale = _sale.ToList(); //to avoid n+1 queries in case of grouping

// Run through lstSale here
foreach(var item in lstSale)
{
  Console.WriteLine(item);
}

var sale2 = from x in lstSale
            group x by new { x.SKUID, x.EmployeeName } into grouping
            select new 
            {
                 EmployeeName = grouping.Key.EmployeeName,
                 SKUID = grouping.Key.SKUID,
                 SKUName = grouping.SKUName,
                 MonthSale =(double?)grouping
                          .Where(x => x.StartDate.Month == 2 && 
                                      x.StartDate.Year == 2012)
                          .Select(t=>t.SalesQuantity)
                          .Sum(t=>t.Value)?? 0,
                 MonthSaleValue = (double?)grouping
                          .Where(x => x.StartDate.Month == 2 && 
                                      x.StartDate.Year == 2012)
                          .Sum(x => x.SalesQuantity * x.ExFactoryPrice)  
                             ?? 0,
            };
Console.WriteLine(sale2.OrderBy(x => x.SKUName).ToList());

更改(可能并非全部有效):
1. 删除品牌,因为它没有在第二个查询中使用(您可以将其用作第一个查询中的连接,但如果它是限制的一部分,则不要添加到新类型)
2. 简化了第一个查询生成的匿名类型中包含的内容 - 如果您只使用部分 emp/sales/price,那么它可能会更清楚地了解正在发生的事情
3. 在第一部分中添加了对 SalesMonth 的限制(您在第二部分中所做的事情),因为这可能会减少您的数据、提高性能并让您专注于实际出了什么问题(我已经保留了第二个 SalesMonth 限制)
4. 我假设 SKUID 是 sk 用于分组的相关部分,并不是所有的对象都是必需的

【讨论】:

  • ToList() 运行查询,所以不需要使用foreach。
  • foreach 的重点是让您可以在中间步骤看到列表中的内容。不是强制执行查询。
  • 好的,但是对于观看列表OP只需使用快速观看。
【解决方案2】:

首先调查为var lstSale = _sale.ToList(); 生成的 SQL

如果是 Linq-To-SQL,您可以使用:

context.Log = Console.Out;

如果是 EntityFramework ObjectContext API,您可以使用

Console.WriteLine(((ObjectQuery)_sale).ToTraceString());

或 DbContext API

Console.WriteLine(_sale.ToString());

提供者处理您的 Linq 查询的方式可能会有所不同,如果不挖掘 int SQL 命令,这些查询将不可见。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-05
    • 1970-01-01
    • 2011-04-27
    • 2011-01-15
    • 2017-08-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多