10 LINQ神話

神話#1



すべてのLINQクエリは、キーワード「var」で始まる必要があります。 基本的に、 'var'キーワードの主な目的は、LINQクエリを開始することです!



varキーワードとLINQはスタンドアロンの概念です。 varキーワードを使用すると、コンパイラは初期割り当て(暗黙的な型指定)に基づいてローカル変数の型を推測できます 。 たとえば、次のコード:



var s = "Hello";
      
      





以下と完全に同等:



 string s = "Hello";
      
      





これは、コンパイラが変数sの型をstringとして推論するためです。

同様に、次のクエリ:



 string[] people = new [] { "Tom", "Dick", "Harry" }; var filteredPeople = people.Where (p => p.Length > 3);
      
      





以下と完全に同等:



 string[] people = new [] { "Tom", "Dick", "Harry" }; IEnumerable<string> filteredPeople = people.Where (p => p.Length > 3);
      
      





varキーワードで達成したことは、 IEnumerable <string>の略語を作成することだけだったことがわかります 。 このレコードは短いので多くの人が気に入っています。 他の人は、暗黙的な型付けによりコードが理解しにくくなると信じています。



LINQクエリ varキーワードが必要な場合があります。 これは、匿名型に投影されときに発生します。



 string[] people = new [] { "Tom", "Dick", "Harry" }; var filteredPeople = people.Select (p => new { Name = p, p.Length });
      
      





次の例は、LINQコンテキストの外部で匿名型を使用する方法を示しています。



 var person = new { Name = "Foo", Length = 3 };
      
      





神話#2



すべてのLINQクエリはクエリ構文を使用する必要があります。



LINQクエリを作成するには、 ラムダ構文クエリ構文の 2つの方法があります



ラムダ構文の例:



 string[] people = new [] { "Tom", "Dick", "Harry" }; var filteredPeople = people.Where (p => p.Length > 3);
      
      





前の例に似ていますが、 クエリ構文を使用した例:



 string[] people = new [] { "Tom", "Dick", "Harry" }; var filteredPeople = from p in people where p.Length > 3 select p;
      
      





論理的には、コンパイラはクエリ構文をラムダ構文に変換します。 つまり、クエリ構文を使用して表現できるものはすべてラムダ構文でも表現できます。 クエリ構文は、複数の範囲変数を含むクエリを使用すると、はるかに簡単になります 。 (この例では、範囲pの変数を1つだけ使用しているため、両方のクエリは同じように単純に見えます)。



クエリ構文ですべての演算子を使用できるわけではないため、これらの2種類の構文は互いに補完する可能性が高くなります。 全員から最高の結果を得るために、1つの式にクエリスタイルを混在させることができます(神話#5を参照)。



神話#3



テーブルからすべてのクライアントを抽出するには、次のようなクエリを使用する必要があります。

var query = db.Customersのcからcを選択します。



表現



 from c in db.Customers select c
      
      





冗長すぎる! 単に使用できます:



 db.Customers
      
      





同様に、次のLINQ to XMLクエリ:



 var xe = from e in myXDocument.Descendants ("phone") select e;
      
      





次のように簡略化できます。



 var xe = myXDocument.Descendants ("phone");
      
      





そして、このリクエスト:



 Customer customer = (from c in db.Customers where c.ID == 123 select c) .Single();
      
      





次のように簡略化できます。



 Customer customer = db.Customers.Single (c => c.ID == 123);
      
      





神話#4



LINQでSQLクエリを再現するには、LINQクエリをできるだけSQLクエリに似たものにする必要があります。



LINQとSQLは、異なる概念を使用する異なる言語です。



おそらく、LINQの生産的な使用に対する主な障壁は、「SQL用語で考える」シンドロームです。SQLでクエリをメンタルに提示し、それをLINQに変換します。 結果は、APIとの絶え間ない闘争になります!



LINQの用語だけで考え始めると、クエリとSQLのクエリとの共通点はほとんどなくなります。 多くの場合、それらはさらに単純になります。



神話#5



LINQで効率的に参加するには、joinキーワードを使用する必要があります。



これは本当ですが、ローカルコレクションのクエリに対してのみです。 データベースクエリを作成する場合、joinキーワードはまったく必要ありません。結合操作は、複数のfromとサブクエリを使用して置き換えることができます。 いくつかのfrom-sおよびサブクエリはより普遍的です。非等価結合接続を実装することもできます



さらに、LINQ to SQLおよびEntity Frameworkでは、結合の必要性を減らす関連付けプロパティを要求できます! たとえば、次のコードは、一度も購入していないすべての顧客の名前と識別子を抽出する方法を示しています。



 from c in db.Customers where !c.Purchases.Any() select new { c.ID, c.Name }
      
      





または、1000ドル以上の価値のある購入を行っていない顧客を抽出します。



 from c in db.Customers where !c.Purchases.Any (p => p.Price > 1000) select new { c.ID, c.Name }
      
      





ラムダ構文とクエリ構文が混在していることに注意してください。 関連プロパティ、接続ガイド、および混合構文のその他の例については、 LINQPadを参照してください。



神話#6



SQLクエリの結果はフラットデータセットなので、LINQクエリはフラットデータセットも返すように作成する必要があります。



これは神話#4の結果です。 LINQの主な利点の1つは、次のことができることです。

  1. 手動で接続する代わりに、関連付けプロパティを介して構造化オブジェクトを要求します。
  2. オブジェクト階層に直接投影します。


原則として、1と2は独立していますが、1は2に役立ちます。たとえば、WAの顧客番号とその購入を取得する場合、次のコードを使用できます。



 from c in db.Customers where c.State == "WA" select new { c.Name, c.Purchases // An EntitySet (collection) }
      
      





このクエリの階層結果は、フラットデータセットよりもはるかに簡単に機能します。



アソシエーションプロパティを使用せずに同じ結果を達成できます



 from c in db.Customers where c.State == "WA" select new { c.Name, Purchases = db.Purchases.Where (p => p.CustomerID == c.ID) }
      
      







神話#7



LINQ to SQLで外部結合を実装するには、常にDefaultIfEmpty()演算子を使用する必要があります。



これは、 フラットデータセットが必要場合に当てはまります。 前の神話の例は、SQLの左外部結合に変換され、 DefaultIfEmptyステートメントを必要としません。



神話#8



LINQ to SQLまたはEntity Frameworkクエリは、1ステップで構築された場合にのみユニットとして実行されます。



LINQは遅延実行モデルを使用します。つまり、クエリは作成時ではなく、 列挙時に実行されます。 これは、必要な数の手順でクエリを作成でき、結果の使用を開始するまでサーバーに到達しないことを意味します。



たとえば、次のクエリは、名前が文字「A」で始まる2つの購入を行ったすべての顧客の名前を取得します。 このクエリは3つの手順で作成しました。



 var query = db.Customers.Where (c => c.Name.StartsWith ("A")); query = query.Where (c => c.Purchases.Count() >= 2); var result = query.Select (c => c.Name); foreach (string name in result) //     ! Console.WriteLine (name);
      
      







神話#9



メソッドは、「new」演算子で終了する場合、リクエストを返すことはできません。



トリックは、オブジェクト初期化子を使用して通常の名前付き型に投影することです。



 public IQueryable<NameDetails> GetCustomerNamesInState (string state) { return from c in Customer where c.State == state select new NameDetails { FirstName = c.FirstName, LastName = c.LastName }; }
      
      





NameDetailsクラス次のように定義されます。



 public class NameDetails { public string FirstName, LastName; }
      
      





神話#10



LINQ to SQLを使用する最良の方法は、DataContextクラスの単一インスタンスを静的プロパティでインスタンス化し、この共有インスタンスをアプリケーションの使用中ずっと使用することです。



DataContextインスタンスによって監視されるオブジェクトは、リクエストが繰り返されても更新されないため、このような戦略は古いデータにつながります。



DataContextクラスの単一のインスタンスを使用すると、スレッドセーフではないため、多くの問題が発生します。



適切な戦略は、オブジェクトに対する要求ごとにDataContextの新しいインスタンスを作成し、その寿命を非常に短くすることです。 Entity Frameworkについても同じことが言えます。



この記事に加えて、ブログに投稿した LINQクイズ(テスト)も翻訳しました( 回答 )。 ジョー・アルバハリの質問に対する答えを議論することは非常に有用で興味深いと思います!



All Articles