簡體   English   中英

如果可能有空集,如何進行Linq聚合?

[英]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)

這里有兩個問題:

  1. Sum()重載
  2. LINQ to SQL遵循SQL語義,而不是C#語義。

在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM