web-dev-qa-db-ja.com

タイプのカウントを取得しようとすると、LINQクエリが例外をスローするのはなぜですか

public readonly IEnumerable<string> PeriodToSelect = new string[] { "MONTH" };  

var dataCollection = from p in somedata    
from h in p.somemoredate    
where h.Year > (DateTime.Now.Year - 2)    
where PeriodToSelect.Contains(h.TimePeriod)  
select new  
{  
    p.Currency, 
    h.Year.Month, h.Value                                                    
}; 

次のコード行で例外がスローされる理由を誰かに教えてもらえますか?

int count = dataCollection.Count();  

これは例外です:

System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Linq.Enumerable.<SelectManyIterator>d__31`3.MoveNext()
   at System.Linq.Enumerable.<SelectManyIterator>d__31`3.MoveNext()
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at ...
15
thenth

LINQは遅延実行を使用し、実際のLINQクエリは.Count().ToList()などを呼び出すまで実行されないため、例外はCount()ステートメントでスローされます。

2
Albin Sunnanbo

これは、述語または射影を実行しようとしている間、linq2objectsの通常のnull参照例外のように見えます。

「somedata」コレクションの一部の要素がnullの場合、「h.Year」がnullの場合(これはどのタイプですか?)、または「p。 somemoredate」はnullです。

12
Diego V

延期された実行が再びストライキ!

(最初に、これはコレクションのどこかでp.somemoredateがnullであることが原因であると推測されます。)

あなたの例を考えると、クエリされているビットを単純化したので、私たちが本当に知る方法はありません。それを正面から見ると、「somedata」または「somemoredate」が何であれ、あなたが見る必要があるものであると言えます。

これを理解するために、(本当に必死になったら)クエリをパーツに分割し、例外がスローされる場所を監視します。基本的に遅延実行が一時的に発生するのを「停止」する.ToArray()呼び出しに注意してください。

var sd = somedata.ToArray();
var x  = (from p in sd from h in p.somemoredate.ToArray()).ToArray();  //My guess is that you'll get your exception here.

このように分割すると、例外がスローされる場所と、問題を探す場所を簡単に確認できます。

4
Dave Markle

私は同じ問題に遭遇しました。 MSが集約関数に組み込みのnull検出と処理を提供しなかったことは厄介です。もう1つの問題は、ダッシュボード/レポートで作業していたときに、null /空のクエリ結果に対して0または$ 0の戻り結果を確実に取得したかったことです。これらのテーブルにはすべて最終的にデータが含まれますが、早い段階で多くのnullが返されます。このテーマに関する複数の投稿を読んだ後、私はこれを思いついた:

返したいフィールドを取得するか、後で集計関数を最初に適用します。 nullリターンをテストします。 nullが検出された場合は0を返します。

実際のデータが返される場合は、CountまたはSum集計Linq関数を安全に利用/適用できます。

public ActionResult YourTestMethod()
{
    var linqResults = (from e in db.YourTable
                       select e.FieldYouWantToCount);

    if (linqResults != null)
    {
        return Json(linqResults.ToList().Count(), JsonRequestBehavior.AllowGet);
    }
    else
    {
        return Json(0, JsonRequestBehavior.AllowGet);
    }
}

以下の合計例

public ActionResult YourTestMethod()
{
    var linqResults = (from e in db.YourTable
                       select e.Total);

    if (linqResults != null)
    {
        return Json(linqResults.ToList().Sum(), JsonRequestBehavior.AllowGet);
    }
    else
    {
        return Json(0, JsonRequestBehavior.AllowGet);
    }
}
1
Les Baker