2014-09-23 56 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); 
} 

^^這似乎已顯着提高性能。哦,謝謝你傾聽