[英]How to do Linq aggregates when there might be an empty set?
我有一個Linq的Things
集合,其中Thing
有一個Amount
(十進制)屬性。
我正在嘗試針對特定事物的子集對此進行聚合:
var total = myThings.Sum(t => t.Amount);
這很好用。 但后來我添加了一個條件,讓我在結果中沒有任何東西:
var total = myThings.Where(t => t.OtherProperty == 123).Sum(t => t.Amount);
而不是得到total = 0或null,我得到一個錯誤:
System.InvalidOperationException:無法將null值分配給類型為System.Decimal的成員,該成員是非可空值類型。
這真是令人討厭,因為我沒想到這種行為。 我本來期望總數為零,也許是null - 但肯定不會拋出異常!
我究竟做錯了什么? 什么是解決方法/修復?
編輯 - 例子
感謝大家的評論。 這是一些代碼,復制和粘貼(未簡化)。 它是LinqToSql(也許這就是為什么你無法重現我的問題):
var claims = Claim.Where(cl => cl.ID < 0);
var count = claims.Count(); // count=0
var sum = claims.Sum(cl => cl.ClaimedAmount); // throws exception
我可以使用針對Northwind的以下LINQPad查詢重現您的問題:
Employees.Where(e => e.EmployeeID == -999).Sum(e => e.EmployeeID)
這里有兩個問題:
Sum()
重載 在SQL中, SUM(no rows)
返回null
,而不是零。 但是,查詢的類型推斷會將decimal
作為類型參數而不是decimal?
。 修復是幫助類型推斷選擇正確的類型,即:
Employees.Where(e => e.EmployeeID == -999).Sum(e => (int?)e.EmployeeID)
現在將使用正確的Sum()
重載。
要獲得不可為空的結果,您需要將數量轉換為可空類型,然后處理Sum
返回null的情況。
decimal total = myThings.Sum(t => (decimal?)t.Amount) ?? 0;
還有另一個專門討論(ir)理由的問題 。
它會拋出異常,因為組合的sql查詢的結果為null,並且無法將其分配給decimal var。 如果你執行了以下操作,那么你的變量將為null(我假設ClaimedAmount是十進制的):
var claims = Claim.Where(cl => cl.ID < 0);
var count = claims.Count(); // count=0
var sum = claims.Sum(cl => cl.ClaimedAmount as decimal?);
那么你應該得到你想要的功能。
您也可以在where語句的位置執行ToList(),然后總和將返回0,但這將違背其他地方關於LINQ聚合的說法。
如果t具有類似'HasValue'的屬性,那么我將表達式更改為:
var total =
myThings.Where(t => (t.HasValue) && (t.OtherProperty == 123)).Sum(t => t.Amount);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.