2015-01-09 28 views
12

これらの行を含む大きなEntity Frameworkクエリがあります。私は、データを実体化するとEntity FrameworkクエリでSum()が返される

var programs = from p in Repository.Query<Program>() 
       where p.OfficeId == CurrentOffice.Id 
       let totalCharges = p.ProgramBillings.Where(b => b.Amount > 0 && b.DeletedDate == null).Select(b => b.Amount).Sum() 
       let totalCredits = p.ProgramBillings.Where(b => b.Amount < 0 && b.DeletedDate == null).Select(b => -b.Amount).Sum() 
       let billingBalance = (totalCharges - totalCredits) 

、私は次のエラーを取得する:

The cast to value type 'Decimal' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type.

次のように私は(2つのタイプキャストで追加)私のクエリを変更すると、エラーが消えます。

var programs = from p in Repository.Query<Program>() 
       where p.OfficeId == CurrentOffice.Id 
       let totalCharges = (decimal?)p.ProgramBillings.Where(b => b.Amount > 0 && b.DeletedDate == null).Select(b => b.Amount).Sum() 
       let totalCredits = (decimal?)p.ProgramBillings.Where(b => b.Amount < 0 && b.DeletedDate == null).Select(b => -b.Amount).Sum() 
       let billingBalance = (totalCharges - totalCredits) 

これはわかりません。 ProgramBilling.Amountはnullを入力できないDecimalです。 Sum()コールにカーソルを合わせると、IntellisenseはDecimal型を返します。さらに2番目のバージョンでは、ProgramBillingsにデータがない行では、totalChargestotalCreditsの両方がnullに設定されていることが確認されました。

質問:

  1. 私はSum()は空のコレクションのために0を返さ理解。どのような状況でこれは真実ではありませんか?

  2. そして、それが真実でない場合、Sum()にカーソルを置くと、IntellisenseはDecimalではなくDecimal型を返します。インテリセンスには、私が持っていたのと同じ理解があったようです。

EDIT:

簡単に修正がSum() ?? 0mような何かをしていることと思われます。あなたはここにそうであるように、オブジェクトにLINQを使用していない場合は

Operator '??' cannot be applied to operands of type 'decimal' and 'decimal'

+3

あなたはこの投稿を参照してください:http://stackoverflow.com/questions/17593371/how-to-force-linq-sum-to-return-0-while-source-collection-is-empty –

+0

@ジョナサンウッド: "しかし、私はまだこれがなぜ必要かについて混乱しています"再びリンクされた質問のタイトルを読んでください。コレクションが空であるために必要です。空でないコレクションの合計がnullでない場合、あなたは何を期待しますか?明らかに、「0」は合計に対して完全に有効な値であるため、「0」はそれをカットしない。 –

+0

@DavidTansey:私はそれを見ましたが、私の質問の終わりに私が質問する質問のいずれかについての手がかりを提供しません。これは、必要に応じて私が取るアプローチです。理由を理解したかっただけです。 –

答えて

8

I understood Sum() returned 0 for an empty collection. Under what circumstances is this not true?

:しかし、それは私にエラーを与え、違法です。ここでは、このクエリをSQLに変換するクエリプロバイダがあります。 SQL操作には、そのSUM演算子のセマンティクスが異なります。

And if sometimes that is not true, then why when I hover over Sum(), Intellisense shows it returns type Decimal and not Decimal? It appears Intellisense had the same understanding that I had.

C#LINQ SUM演算子はNULL値を返しません。 NULL以外の値が必要ですが、SQL SUM演算子のセマンティクスが異なる場合は、0ではなく、空集合を合計するとnullを返します。 nullの値が、C#がnull以外の値を必要とするコンテキストで提供されているという事実は、すべてが壊れているすべての理由です。ここでC#LINQ SUM演算子がnull値を返した場合は、nullが問題なく返されます。

C#演算子と、このエラーを引き起こしている表現に使用されているSQL演算子の違いは、次のとおりです。コレクションが空のとき、私は私のEFクエリのいずれかで同じ問題を持っている

+0

説明をありがとう。私はそれがC#とSQLのセマンティクスの違いに関係していると仮定しましたが、コンパイラがここでC#のセマンティクスを取るという欠点のようです。そうでなければ、合体演算子を使用してnull戻り値をゼロにすることができます。 –

+0

@ JonathanWood LINQは、今までどこでも照会できるあらゆるもののセマンティクスをサポートできません。試してみると、事実上使用できないほど多くのことが起こります。サポートするオペレーションのタイプ、サポートしないセマンティクス、サポートするセマンティクスを決定する必要がありました。その後、LINQで記述できる操作を、照会しているものにマッピングするために、照会プロバイダーの責任となります。この状況の現実は、すべてが1:1にマップされないということです。 – Servy

+0

私はそれを理解していますが、その場合は、それほど厳密に型付けされていない構文の呼び出しを呼びます。とにかく、私はこれの説明を見つけるのが難しかった。そしてその質問はかなり注目を集めました。再度、感謝します。 –

0

、このための1つのクイックフィックスは、null許容のDecimalにキャストすることです:

var total = db.PaiementSet.Sum(o => (Decimal?)o.amount) ?? 0M; 

はそれが役に立てば幸い。

+0

私のために働かなかった。 – Sentinel

0

.Sumを追加する前に、DefaultIfEmpty(0。0M)