2012-04-06 12 views
2

まず、この質問に対する回答を検索しましたが、私が使用している機能が何であるかわからないため、何も見つかりませんでした。LINQ:返されるオブジェクトに新しいオブジェクトを宣言できないのはなぜですか?

以下のコードのDBEntitiesは、Oracle DB接続のためにdevartによって生成されたものです。

最初の例は正常に動作し、2番目の例ではなぜSystem.NullReferenceExceptionが返されますか?

有効コード:

using (DBEntities context = new DBEntities()) 
{ 
    var infos = (from info in context.Infos 
       where info.Index == index 
       orderby info.Name 
       select new 
       { 
        Name = info.Name, 
        MRN = info.MRN, 
        UnitNumber = (info.UnitNum == null) ? -1 : (decimal)info.UnitNum, 
        UnitName = (info.UnitName == null) ? String.Empty : info.UnitName 
       }).Distinct(); 

    foreach (var info in infos) 
    { 
     // *do stuff* 
    } 
} 

コード(foreachのに達すると、例外のみ見られます)例外を与える:

using (DBEntities context = new DBEntities()) 
{ 
    var infos = (from info in context.Infos 
       where info.Index == index 
       orderby info.Name 
       select new Member() 
       { 
        Name = info.Name, 
        MRN = info.MRN, 
        CurrentUnit = new Unit() 
        { 
         UnitNumber = (info.UnitNum == null) ? -1 : (decimal)info.UnitNum, 
         UnitName = (info.UnitName == null) ? String.Empty : info.UnitName 
        } 
       }).Distinct(); 

    foreach (Member info in infos) 
    { 
     // *do stuff* 
    } 
} 

EDIT: は、私はこのことを追加したいです同様に機能する:

using (DBEntities context = new DBEntities()) 
{ 
    var infos = (from info in context.Infos 
       where info.Index == index 
       orderby info.Name 
       select new Member() 
       { 
        Name = info.Name, 
        MRN = info.MRN 
       }).Distinct(); 

    foreach (Member info in infos) //Exception is thrown here. 
    { 
     // *do stuff* 
    } 
} 
+4

例外はありますか? – Thebigcheeze

+0

@Thebigcheeze System.NullReferenceException – bsara

+0

あなたのコレクションにデータが含まれていますか? – Tigran

答えて

2

最初のものは、SQLからこれらの匿名型を戻すことができ、EFが式全体のSQL文を生成できるためです。 2番目の方法は、SQLでMemberクラスのインスタンスを作成できないためではありません。 (AsEnumerable()を使用して)列挙を強制すると、Member valueクライアント側を作成できます。

LINQは設計上、完全に「遅延」であるため、例外は常に列挙の時点でスローされます。式を作成した時点(テスト目的など)で強制的に実行したい場合は、末尾に.ToList()を追加します。代わりに

foreach (Member info in infos) //Exception is thrown here. 
{ 
    // *do stuff* 
} 

使用

foreach (var info in infos) //Valid. 
{ 
    // *do stuff* 
} 

これが原因infosリターンanonymus結果であるの

+0

だから、エンティティでLINQを使用するときCurrentUnitで行うようにオブジェクトの新しいインスタンスを作成しますが、Enumerableオブジェクトでそれを実行していればできますか?ただ明確にする。 – bsara

+0

いいえ、彼はあなたの特定の状況において、Linqに現在値が必要であることを伝えることによって、Linqに強制的に実行させなければならないと言っています。 –

+2

クエリ式のどの部分がデータベース上で評価され、クライアント上で評価されるかを常に考えます。 .ToList()、.ToArray()、.AsEnumerable()の前のものはSQL Server上で実行されるため、式を評価できない場合は失敗します。 EFは境界をどこに置くべきかを決める試みはしませんし、SQLでできるだけ多くのことができると仮定しているだけです。 –

0

。これは完全にMemberコレクションクラスではありません。

+0

しかし 'foreachの(メンバー...'との例では、クエリは、 'Member'インスタンスではなく、匿名のインスタンス。 – phoog

+2

@phoogをインスタンス化します。あなたは完全修飾されたメンバーのコレクションクラスを反復していない。同様にリストコレクションクラス。つまりなぜ、あなたはMemberクラスの代わりにvarを使わなければならないのですか? – wonde

+1

それはちょっと真実ではありません。select節で 'select new Member()'というクエリがある場合、 'IEnumerable 'と 'foreach(Member。 .. 'はうまくいきます。別の理由で例外が発生しています(Hightechriderの答えを参照してください)。 – phoog

関連する問題