2017-07-28 71 views
0

我有一個列表Customers,每個人都有一個列表Orders。每個Order都有一個LineItems的列表。如何根據訂單的價值獲得排名前10的客戶

我想編寫一個LINQ查詢,根據訂單價值(即花費的金額),而不是訂單總數,讓我成爲前10名客戶。

一個客戶可能有2個訂單,但可能花費了10,000英鎊,但另一個客戶可能有100個訂單,並且只花費了500英鎊。

現在,我有這個讓訂單數量排在前10位的客戶。

var customers = (from c in _context.Customers where c.SaleOrders.Count > 0 
     let activeCount = c.SaleOrders.Count(so => so.Status != SaleOrderStatus.Cancelled) 
     orderby activeCount descending 
     select c).Take(10); 

UPDATE

由於喬恩斯基特的這樣做了雙Sum評論,我寫了下面的查詢來編譯。

var customers = (from c in _context.Customers where c.SaleOrders.Count > 0 
     let orderSum = c.SaleOrders.Where(so => so.Status != SaleOrderStatus.Cancelled) 
            .Sum(so => so.LineItems.Sum(li => li.CalculateTotal())) 
     orderby orderSum descending 
     select c).Take(10); 

但是當我運行它,我得到以下錯誤:

LINQ doesn't recognise method on entity

看來LINQ不承認我的.CalculateTotal()方法,它坐在我的LineItem.cs實體。

+0

因此,而不是使用'Count'你需要使用'Sum'總結這些訂單的價值...... –

+0

我試過了,但因爲名單沒有工作'LineItem'實體是需要總結的,不是嗎? – Ciwan

+0

您應該準確顯示您嘗試過的內容 - 有可能需要兩次*(每個訂單一次,然後一次總計訂單總計...) –

回答

1

你看到的問題是,CalculateTotal()不是Linq可以轉換成SQL(這是在運行時完成的,因此沒有編譯器錯誤)。

這裏的關鍵問題是,LINQ的並沒有真正的lambda表達式(Func<>)工作,但實際上表達式(Expression<Func<>>),這是在部分編譯狀態,其中的LINQ然後去約拆卸和轉換成SQL代碼。

所以,讓我們假設CalculateTotal是這樣定義的成員函數:

public decimal CalculateTotal() 
{ 
     return this.quantity * this.value; 
} 

我們可以定義爲本地lambda函數

Func<LineItem, decimal> CalculateTotal = (li => li.quantity * li.value); 

現在,我們有一個lambda,這需要的LineItem並返回一個值,這正是Sum()想要的,所以現在我們可以替換:

.Sum(so => so.LineItems.Sum(li => li.CalculateTotal())) 

.Sum(so => so.LineItems.Sum(CalculateTotal)) 

但是,這會崩潰,只是因爲它是因爲,正如我所說,它希望有一個表達以前那樣。所以,我們給它一個:

Expression<Func<LineItem, decimal>> CalculateTotal = (li => li.quantity * li.value);