2014-09-23 50 views
0

我有两个表:优化LINQ,而不是创建新的集合/回路

发票(InvoiceID,InvoiceNumber)
Invoices_Products(InvoiceID,产品ID,IsFinalized)

我展示列表所有发票,并且有按钮可以通过“定稿”或“未定稿”发票进行过滤。最终发票是产品是IsFinalized==true

此刻,我有以下代码正在执行非常慢:

IEnumerable<Invoice> invoices = db.Invoices; 

if (isFinalized) // filter by finalized invoices 
{ 
    List<Invoice> unfinalizedInvoices = new List<Invoice>(); 

    foreach (var invoice in invoices) 
    { 
     int invoicesProductsCountTotal = db.Invoices_Products.Where(l => l.InvoiceID == invoice.InvoiceID).Count(); 
     int invoicesProductsCountFinalized = db.Invoices_Products.Where(l => l.InvoiceID == invoice.InvoiceID && l.IsFinalized == true).Count(); 

     if (invoicesProductsCountTotal != invoicesProductsCountFinalized) 
     { 
      unfinalizedInvoices.Add(invoice); 
     } 
    } 

    invoices = invoices.Except(unfinalizedInvoices); 
} 
else 
{ 
    List<Invoice> finalizedInvoices = new List<Invoice>(); 

    foreach (var invoice in invoices) 
    { 
     int invoicesProductsCountTotal = db.Invoices_Products.Where(l => l.InvoiceID == invoice.InvoiceID).Count(); 
     int invoicesProductsCountFinalized = db.Invoices_Products.Where(l => l.InvoiceID == invoice.InvoiceID && l.IsFinalized == true).Count(); 

     if (invoicesProductsCountTotal == invoicesProductsCountFinalized && invoicesProductsCountFinalized > 0) 
     { 
      finalizedInvoices.Add(invoice); 
     } 
    } 

    invoices = invoices.Except(finalizedInvoices); 
} 

我知道这是不是最佳的,但我喜欢传播我的LINQ,这样我可以阅读和理解它。
我的问题:有没有什么办法可以使这个查询更快使用.All.Any什么的,或者我需要重新考虑我的数据库设计(可能增加一个额外的列在发票表)

编辑:第三张表是产品(ProductID,ProductNumber),但您知道

回答

1

目前您正在加载所有发票,然后为每张发票加载产品。这肯定会很慢(当你开始添加大量发票时,速度会变慢)。

您应该在EntityFramework中创建一个多对多的关系。 (见example

你的类应该是这样的:

class Invoice 
{ 
    List<Product> Products {get; set;} 
} 
class Product 
{ 
    bool IsFinalized {get; set;} 
} 

现在你可以使用LINQ来确保只有SQL语句只执行数据你想要的获取:

var invoices = db.Invoices.Where(i => i.Products.All(p => p.IsFinalized == finalized)); 
+0

谢谢。但是我用'Invoices_Products'作为许多一对多连接表 - 它拥有像“数量”,“SellingPrice”等。(顺便说一句,我没有使用代码第一 - 第一个使用数据库)数列 – user982119 2014-09-23 15:42:12

+0

您仍然可以做到这一点,但不是多对多,而是定义两个一对多的关系。然后你可以用LINQ来遍历它 – Kenneth 2014-09-23 16:01:35

0

遍历每个Invoice,然后向数据库发出额外的请求将非常缓慢。让您的查询一次获取所有信息,然后遍历结果。

var result = from invoice in db.Invoices 
      join invoicedProduct in db.Invoices_Products 
       on invoice.InvoiceId equals invoicedProduct.InvoiceId 
      select new 
      { 
       InvoiceId = invoice.InvoiceId, 
       ProductId = invoicedProduct.ProductId, 
       IsFinalized = invoicedProuct.IsFinalized 
      }; 

var grpResult = from record in result 
       group record by record.ProductId into productGrp 
       select productGrp; 

foreach(var grp in grpResult) 
{ 
    Console.WriteLine("ProductId: " + grp.Key.ToString()); 
    Console.WriteLine("TotalCount: " + grp.Count().ToString()); 
    Console.WriteLine("Finalized: " + grp.Where(item => item.IsFinalized).Count().ToString()); 
} 
+0

与其使用'Join'后跟一个'GroupBy',你应该从一开始就使用'GroupJoin'。 – Servy 2014-09-23 15:47:07

+0

@Viper,ta的洞察力 – user982119 2014-09-23 15:56:05

+0

@Servy是否有所作为?直到foreach才会执行第一条语句。从未使用过'GroupJoin' btw;) – Viper 2014-09-23 15:57:46

0
if (isFinalized) 
{ 
    invoices = invoices.Where(l => l.Invoices_Products.All(m => m.IsFinalized == true)); 
} 
else 
{ 
    List<Invoice> finalizedInvoices = invoices.Where(l => l.Invoices_Products.All(m => m.IsFinalized == true)).ToList(); 
    invoices = invoices.Except(finalizedInvoices); 
} 

^^这似乎已显着提高性能。哦,谢谢你倾听