マテリアライズド値がnullであるため、値タイプ 'Int32'へのキャストは失敗しました


192

次のコードがあります。エラーが発生します:

「値の型 'Int32'へのキャストは、実体化された値がnullであるため失敗しました。結果の型のジェネリックパラメーターまたはクエリでnull可能な型を使用する必要があります。」

CreditHistoryテーブルにレコードがない場合。

var creditsSum = (from u in context.User
                  join ch in context.CreditHistory on u.ID equals ch.UserID                                        
                  where u.ID == userID
                  select ch.Amount).Sum();

null値を受け入れるようにクエリを変更するにはどうすればよいですか?

回答:


328

linq-to-sqlクエリはコードとして実行されるのではなく、SQLに変換されます。これは、予期しない動作を引き起こす「漏れやすい抽象化」である場合があります。

そのようなケースの1つはnull処理で、さまざまな場所に予期しないnullが存在する可能性があります。...DefaultIfEmpty(0).Sum(0)この(非常に単純な)場合に役立ちSUMますnull。c#は0を期待しますが、要素とsqlの戻り値はありません。

より一般的なアプローチは、生成されたSQLが予期しないnullを返すリスクがある場合はいつでも??変換さCOALESCEれるを使用することです。

var creditsSum = (from u in context.User
              join ch in context.CreditHistory on u.ID equals ch.UserID                                        
              where u.ID == userID
              select (int?)ch.Amount).Sum() ?? 0;

これは最初にキャストしint?て、C#コンパイラに、この式が実際にを返しnullても、がSum()返されることを伝えますint。次に、通常の??演算子を使用してnullケースを処理します。

この回答に基づいて、LINQ to SQLとLINQ to Entitiesの両方の詳細をブログに投稿しました。


3
Andersに感謝します。DefaultIfEmpty(0).Sum()を使用したソリューションは、私にとってはうまく機能します。(int?)で2番目の解決策も試しました... ?? 0 ...が、それは以前と同じ例外がスローされます。..
zosim

ようやくこれをテストして調整したので、2番目のバージョンも機能します。
Anders Abel

1
Sum()およびその他の集約関数は、空のデータセットに適用されるとnullを返します。それらの定義とは逆に、実際には、基礎となる型のnull許容バージョンを返します。
Suncat2000 14

2
@recursive:例はLINQ-to-Objectsであり、LINQ-to-SQL(またはLINQ-to-Entities)ではありません。基盤となるデータプロバイダーによって、動作が異なります。
Suncat2000、2015

これは良い考えでした。nullオブジェクトを返すようにreturnオブジェクトを更新しましたが、これはチャームとして機能しました。
Kremena Lalova、2015

8

null可能Amountフィールドを許可するには、null合体演算子を使用してnullを0に変換します。

var creditsSum = (from u in context.User
              join ch in context.CreditHistory on u.ID equals ch.UserID                                        
              where u.ID == userID
              select ch.Amount ?? 0).Sum();

1
私があなたのチップを使うとき、コンパイラは言います:演算子 '??' タイプ「int」および「int」のオペランドには適用できません。何か忘れましたか?
ゾシム

@zosim:それがint?最初にキャストを追加する理由です。
アンデルスアベル

intを追加しましたが、同じ例外です。あなたが開発環境を持つとき、私はあなたに感謝します。この構文のどこが間違っているかを確認します。
ゾシム

1
@zosim:私は問題を理解していません。がの場合Amountintnullにできないことはすでにわかっているため、結合は不要です。あなたが言ったエラーを受け取ってAmountいるなら、それはnull可能ではありません、それは単なるintです。
再帰的

1
@recursive:量はintで、大丈夫です。金額はすでに価値があります。上記のエラーはCreditHistoryテーブルが空であるために発生したと思います。Userテーブルに1つのレコードがあり、CreditHistoryテーブルに0のレコードがあるため、エラーが発生します。DefaultIfEmpty(0).Sum()を使用すると正常に動作しますが、?? 0エラーをスローします。私の別の質問は、この場合のベストプラクティスは何ですか?DefaultIfEmpty(0)?感謝
ゾシム2011

4

aggregateアクションを実行するアイテムを取得しない関数を使用しています。linqクエリが次のような結果を与えていることを確認する必要があります。

var maxOrderLevel =sdv.Any()? sdv.Max(s => s.nOrderLevel):0

11
これにより、sdvが2回実行されます。これはIQueryablesに必要なものではありません
Ody

4

ビューから選択しようとしたときにこのエラーメッセージが表示されました。

問題は、ビューが最近いくつかの新しいnull行(SubscriberId列)を取得し、EDMX(EFデータベースが最初)で更新されなかったことでした。

カラムは、機能するためにNullableタイプである必要がありました。

var Dealer = Context.Dealers.Where(x => x.dealerCode == DealerCode).FirstOrDefault();

ビューの更新前:

public int SubscriberId { get; set; }

ビューの更新後:

public Nullable<int> SubscriberId { get; set; }

EDMXでのビューの削除と追加が機能しました。

それが誰かを助けることを願っています。


また、これは私の問題であり、私の答えだった
サイモン・ニコルズ

4

私はこのコードを使用しましたが、正しく応答し、出力値のみがnull可能です。

var packesCount = await botContext.Sales.Where(s => s.CustomerId == cust.CustomerId && s.Validated)
                                .SumAsync(s => (int?)s.PackesCount);
                            if(packesCount != null)
                            {
                                // your code
                            }
                            else
                            {
                                // your code
                            }

1

この質問にはすでに回答済みです。しかし、それを2つのステートメントに分割したい場合は、以下を検討することができます。

var credits = from u in context.User
              join ch in context.CreditHistory 
                  on u.ID equals ch.UserID                                        
              where u.ID == userID
              select ch;

var creditSum= credits.Sum(x => (int?)x.Amount) ?? 0;

0

Entity Framework 6で実行時にこのコードを使用してこのエラーが発生しました:

var fileEventsSum = db.ImportInformations.Sum(x => x.FileEvents)

LeandroSoaresからの更新:

これを単一実行に使用します。

var fileEventsSum = db.ImportInformations.Sum(x => (int?)x.FileEvents) ?? 0

元の:

これに変更すると、うまくいきました:

var fileEventsSum = db.ImportInformations.Any() ? db.ImportInformations.Sum(x => x.FileEvents) : 0;

1
それを2回実行しませんか?
nawfal

これは良い答えではありません。DBから2回取得します。
Leandro Soares

@nawfalこれは真実ですが、実行時エラーよりもはるかに優れています。linq-to-sqlは絶対に使用できますが、lambdaを使用するとより難しくなります。もちろん例外をキャッチすることもできますが、2つの実行よりも解決策が悪いと思います。
Ogglas

@LeandroSoares上記のコメントを参照
Ogglas

1
@LeandroSoaresいいですね!私は私の答えを更新し、あなたが提供したコードとそれを代わりに使用する理由の説明を使用しました。
オグラス

0

私も同じ問題に直面していて、「?」を使用して列をnull可能にすることで解決しました オペレーター。

Sequnce = db.mstquestionbanks.Where(x => x.IsDeleted == false && x.OrignalFormID == OriginalFormIDint).Select(x=><b>(int?)x.Sequence</b>).Max().ToString();

時々nullが返されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.