[C#] 最大或默認?


Answers

我只是有一個類似的問題,但我在列表上使用LINQ擴展方法而不是查詢語法。 在這裡也可以使用Nullable技巧:

int max = list.Max(i => (int?)i.MyCounter) ?? 0;
Question

從LINQ查詢中獲取可能不返回行的最大值的最佳方法是什麼? 如果我只是這樣做

Dim x = (From y In context.MyTable _
         Where y.MyField = value _
         Select y.MyCounter).Max

查詢返回沒有行時出現錯誤。 我可以

Dim x = (From y In context.MyTable _
         Where y.MyField = value _
         Select y.MyCounter _
         Order By MyCounter Descending).FirstOrDefault

但對於這樣一個簡單的要求,這感覺有些遲鈍。 我錯過了一個更好的方法來做到這一點?

更新:這裡是背後的故事:我試圖從子表中檢索下一個資格計數器(遺留系統,不要讓我開始......)。 每個病人的第一個資格行總是1,第二個是2等等(顯然這不是子表的主鍵)。 所以,我為患者選擇最大現有計數器值,然後將1加到它以創建一個新行。 當沒有現有的子值時,我需要查詢返回0(所以加1會給我一個計數器值1)。 請注意,我不想依賴子行的原始計數,以防遺傳應用程序在計數器值中引入空位(可能)。 我試圖讓這個問題過於通用是不利的。




想想你在問什麼!

{1,2,3,-1,-2,-3}的最大值顯然是3. {2}的最大值明顯是2.但是空集{}的最大值是多少? 顯然這是一個毫無意義的問題。 空集的最大值沒有被定義。 試圖獲得答案是一個數學錯誤。 任何集合的最大值本身都必須是該集合中的一個元素。 空集沒有元素,所以聲稱某個特定的數字是該集中的最大值而不在該集合中是數學矛盾。

正如計算機在程序員要求它除以零時拋出異常的正確行為一樣,所以當程序員要求它取得空集的最大值時,計算機發出異常是正確的行為。 劃分零,取空集的最大值,擺弄spacklerorke,騎著獨角獸到Neverland,都是毫無意義的,不可能的,不明確的。

現在,你究竟想要做什麼?




姍姍來遲,但我有同樣的擔憂...

從原始文章改寫代碼,您需要定義的集合S的最大值

(From y In context.MyTable _
 Where y.MyField = value _
 Select y.MyCounter)

考慮到你最後的評論

我只想說當我沒有記錄可供選擇時,我知道我想要0,這肯定會對最終解決方案產生影響

我可以將你的問題改為:你想要{0 + S}的最大值。 它看起來像concat提出的解決方案在語義上是正確的:-)

var max = new[]{0}
          .Concat((From y In context.MyTable _
                   Where y.MyField = value _
                   Select y.MyCounter))
          .Max();



我認為這個問題是當查詢沒有結果時你想要發生什麼。 如果這是一個例外情況,那麼我會將查詢包裝在try / catch塊中,並處理標準查詢生成的異常。 如果查詢沒有返回結果是可以的,那麼你需要弄清楚你想要的結果是什麼。 這可能是@大衛的答案(或類似​​的東西會起作用)。 也就是說,如果MAX始終為正值,那麼將已知的“壞”值插入列表中,只有在沒有結果時才會被選中。 一般來說,我希望查詢最大限度地獲取一些數據,我會去嘗試/ catch路由,否則你總是被迫檢查你獲得的值是否正確。 我寧願非例外情況只能使用獲得的價值。

Try
   Dim x = (From y In context.MyTable _
            Where y.MyField = value _
            Select y.MyCounter).Max
   ... continue working with x ...
Catch ex As SqlException
       ... do error processing ...
End Try



int max = list.Any() ? list.Max(i => i.MyCounter) : 0;

如果列表中包含任何元素(即不為空),則它將佔用MyCounter字段的最大值,否則將返回0。




decimal Max = (decimal?)(context.MyTable.Select(e => e.MyCounter).Max()) ?? 0;



只是為了讓所有人都知道使用Linq來實體上面的方法是行不通的...

如果你嘗試做類似的事情

var max = new[]{0}
      .Concat((From y In context.MyTable _
               Where y.MyField = value _
               Select y.MyCounter))
      .Max();

它會拋出一個異常:

System.NotSupportedException:LINQ to Entities不支持LINQ表達式節點類型'NewArrayInit'。

我會建議只是在做

(From y In context.MyTable _
                   Where y.MyField = value _
                   Select y.MyCounter))
          .OrderByDescending(x=>x).FirstOrDefault());

如果列表為空,則FirstOrDefault將返回0。




我敲了一個MaxOrDefault擴展方法。 沒有太多內容,但它在Intellisense中的存在是一個有用的提醒, Max在空序列上會導致異常。 另外,如果需要,該方法允許指定默認值。

    public static TResult MaxOrDefault<TSource, TResult>(this 
    IQueryable<TSource> source, Expression<Func<TSource, TResult?>> selector,
    TResult defaultValue = default (TResult)) where TResult : struct
    {
        return source.Max(selector) ?? defaultValue;
    }

用法,用於名為Id int類型的列或屬性:

    sequence.DefaultOrMax(s => (int?)s.Id);