3

以下の最小限のコード例では、どのような動作を説明できますか?与えられたフィールドまたはプロパティに対して、new演算子を使用していても、Entryクラスの同じ2つのインスタンスがLINQ to SQLクエリの各繰り返しで再利用されているようです。同じ問題は、LINQ toオブジェクトクエリでは表示されません。 .NET Framework 4を使用してSQL Server 2005 Enterpriseデータベースに接続するC#コンソールアプリケーションプロジェクトを作成しました。LINQ to SQLクエリで 'new'演算子を使用しましたが、すべての結果で同じインスタンスが参照されています

public class Set 
{ 
    public Entry Field; 
    public Entry Property { get; set; } 
} 

public class Entry 
{ 
    public int ID; 
    public string Name { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var dc = new DataClasses1DataContext(); // just create a simple dbml with some table from some database 
     var resultQuery = (
      from x in dc.SomeTable 
      select new Set() 
      { 
       Field = new Entry(), 
       Property = new Entry() 
      } 
     ); 
     var sets = resultQuery.ToArray(); 
     Test(sets); 

     var source = Enumerable.Range(0, 10); 
     var sourceQuery = (
      from x in source 
      select new Set() 
      { 
       Field = new Entry(), 
       Property = new Entry() 
      } 
     ); 
     var sets2 = sourceQuery.ToArray(); 
     Test(sets2); 
    } 

    static void Test(Set[] sets) 
    { 
     var f = sets[0].Field; 
     Console.WriteLine(sets.All(x => object.Equals(x.Field, f))); 
     var p = sets[0].Property; 
     Console.WriteLine(sets.All(x => object.Equals(x.Property, p))); 
     Console.Writeline(sets.Length); 
     Console.WriteLine(object.Equals(f, p)); 
     Console.WriteLine(); 
    } 
} 

SQLクエリにLINQのためTest()の出力が生成Setオブジェクトのすべてについて、全Fieldメンバーが同じ単一Entryインスタンスを指し、すべてことを示し

True 
True 
1362 
False 

ありますPropertyのメンバーが同じシングルを指していますEntryインスタンス。つまり、同じインスタンスがクエリの各反復でそれぞれのメンバーに再利用されます。

オブジェクトクエリにLINQのためTest()の出力は、新しい個別のインスタンスは、クエリの各反復で作成されていることを示し

False 
False 
10 
False 

あります。

LINQ to SQLの動作が予期されるか、またはバグですか?これがEntity Frameworkで発生するかどうかは誰にも分かりますか?

+0

'dc.SomeTable'に複数の行がありますか?あなたは 'Console.WriteLine(sets.Count());'を追加できますか? –

+0

良い点。はい、私のテストでは何千もの行があります。 'sets.Length> 1'です。 – BlueD

答えて

1

これはバグかどうか、なぜこれがLINQ to SQLで期待されるのか分かりません。 Entity Frameworkでもこの問題が発生した場合は、最後の質問にのみ回答できます。

答えは:あなたがEntryオブジェクトをインスタンス化するときただし、オブジェクト初期化子構文を使用する必要がEFで第

。デフォルトコンストラクタを使用すると、例外につながる:

var resultQuery = (
    from x in dc.SomeTable 
    select new Set 
    { 
     Field = new Entry { Name = "X" }, 
     Property = new Entry { Name = "X" } 
    } 
); 

あなたが初期化する方法は重要ではありません。私はあなたのテストプログラムで、この出力を得る上で(と小さなテストテーブルの4行で)コードを使用する:

False 
False 
4 
False 

False 
False 
10 
False 

これは、中にオブジェクトの具体化に関するSQLとEntity FrameworkのにLINQの間には大きな差があることになります投影。

(私はEF 4.1/DbContextでテストしてみた。)

編集

私は、SQLクエリにあなたのLINQのためにも、上記の私のコードスニペットで変更されたクエリを取得し、生成されたSQLを見る場合私は次の取得:

SELECT 
1 AS [C1], 
N'X' AS [C2], 
N'X' AS [C3] 
FROM [dbo].[SomeTable] AS [Extent1] 
0123:EntitesにLINQと同じ一方

SELECT NULL AS [EMPTY] 
FROM [dbo].[SomeTable] AS [t0] 

このクエリを作成します

私の解釈では、LINQ to SQLは投影コードを解析し、「行変数」xに依存するプロパティ値の列のみを照会します。オブジェクトがマテリアライズされると、他のすべてのプロパティがクライアントに埋められます。オブジェクトが列の値にまったく依存しない場合、LINQ to SQLは単一の定数オブジェクトを作成し、結果コレクション全体で再利用します。

これとは対照的に、Entity Frameworkは、(xに関係なく)定数値をデータベースサーバーに送信します。値はクライアントに返され、EFはそれらの値を列値であるかのように扱い、投影内のオブジェクトのプロパティを更新します。

これは(xの独立して)明らかにランダム関数の値が上で評価されているため、このような何か...

Random random = new Random(); 
var resultQuery = (
    from x in dc.SomeTable 
    select new Set 
    { 
     Field = new Entry { ID = random.Next() }, 
     Property = new Entry { Name = "X" } 
    } 
); 

...は、SQLにLINQで動作大きな違いにもつながりますクライアントに割り当てられ、次にプロパティに割り当てられます。しかし、EFはプロパティ割り当ての右側をSQLに変換してSQLフラグメントとしてデータベースサーバーに送信したいと思っています。これは失敗し、悪名高い "...ストア表現に変換できません..."例外が発生します。

編集2

BTW:まだコレクション全体に単一Fieldインスタンスを作成し、上記最後のコードスニペット:random.Next()は一度だけ評価され(またEntryのコンストラクタのみFieldために一度呼び出されオブジェクト)。このようなコードを記述すると、データベースから返された各行に対してランダムな値を設定したいと思うので、これは本当に混乱します。そうではありません。

関連する問題