統合言語クエリ( LINQ、発音は「リンク」) は、.NET 言語にネイティブ データクエリ機能を追加するMicrosoft .NET Frameworkコンポーネントであり、2007 年に.NET Framework 3.5の主要部分として最初にリリースされました。
LINQ は、 SQL文に似たクエリ式の追加によって言語を拡張し、配列、列挙可能クラス、XMLドキュメント、リレーショナル データベース、およびサードパーティのデータ ソースからデータを簡単に抽出して処理するために使用できます。 クエリ式を任意の計算を読み取り可能に構成するための一般的なフレームワークとして使用するその他の用途には、イベント ハンドラー[1]またはモナドパーサー[2]の構築が含まれます。また、一連のメソッド名 (標準クエリ演算子または標準シーケンス演算子と呼ばれる) と、コンパイラがクエリ構文式をこれらのメソッド名、ラムダ式、および匿名型を使用してFluent スタイルの式(Microsoft ではメソッド構文と呼ばれる)に変換するために使用する変換規則も定義します。
以下では、コレクションを扱うという応用に基づいて演算子について説明します。多くの演算子は、他の関数を引数として受け取ります。これらの関数は、名前付きメソッドまたは匿名関数の形で提供される場合があります。
LINQで定義されたクエリ演算子のセットは、標準クエリ演算子(SQO) APIとしてユーザーに公開されています。このAPIでサポートされているクエリ演算子は次のとおりです。[3]
これらの演算子は、コレクション内の各要素から特定の数値を取得し、それを用いてコレクション内のすべての要素の合計、最小値、最大値、または平均値を求める関数をオプションで受け取ります。オーバーロードされたバージョンは関数を取らず、ラムダ式として単位元が与えられたかのように動作します。
一般化されたSum / Min / Max演算子です。この演算子は、2つの値をどのように組み合わせて中間値または最終値を生成するかを指定する関数を受け取ります。オプションで開始値を指定することにより、集計結果の型を任意に指定できます。さらに、集計結果を別の値に変換する終了関数も指定できます。これは、高階関数 Foldを実装します。
IGrouping<Key, Values>GroupBy演算子は、キー値を抽出し、各キー値に対応するオブジェクトのコレクションを返す関数を受け取ります。これらのIGroupingオブジェクトは、特定のキー値を持つすべてのオブジェクトを列挙するために使用できます。標準クエリ演算子APIでは、コレクションを別の型に変換する演算子も指定されています。[3]
IEnumerable<T>。[4]IQueryable<T>。T[]ToArray:コレクションから配列を作成します。List<T>コレクションから を作成します。Dictionary<K, T>キー K でインデックス付けされたコレクションからを作成します。ユーザー指定の射影関数によって各要素からキーが抽出されます。Lookup<K, T>キー K でインデックス付けされたコレクションからを作成します。ユーザー指定の投影関数によって各要素からキーが抽出されます。IEnumerableコレクションを 型 のいずれかに変換します。または、各要素を 型 から型にキャストすることで、ジェネリックを別のジェネリックに変換します。指定された型にキャストできない要素がある場合は、例外がスローされます。IEnumerable<T>TIEnumerable<T>IEnumerable<R>TRIEnumerableコレクションを のいずれかに変換します。あるいは、各要素を 型 から型にキャストすることで、IEnumerable<T>ジェネリックをIEnumerable<T>別のジェネリックに変換します。どちらの場合も、ターゲット型へのキャストに成功した要素のサブセットのみが対象となります。例外はスローされません。IEnumerable<R>TRLINQは主に.NET Framework 3.5のライブラリとして実装されていますが、クエリを第一級言語構成要素とし、クエリ記述のための糖衣構文を提供するオプションの言語拡張も定義しています。これらの言語拡張は、 C# 3.0、[5] 、 VB 9.0、F# [6]、Oxygeneで最初に実装され、 Nemerleなどの他の言語でも 予備的なサポートが発表されています。言語拡張には以下が含まれます。[7]
var、キーワードを使用して変数を宣言します。VB9.0 では、Dim型宣言なしのキーワードで同じことが実現されます。このようなオブジェクトは依然として強い型付けが行われます。これらのオブジェクトについては、コンパイラが型推論によって変数の型を推論します。これにより、中間変数の型を宣言することなく、クエリの結果を指定および定義できます。SomePropertyたとえば、 10未満
のコレクション内のすべてのオブジェクトを選択するクエリでは、
IEnumerable < MyObject > SomeCollection = /* ここに何か */
IEnumerable < MyObject > results = from c in SomeCollection where c . SomeProperty < 10 select new { c . SomeProperty , c . OtherProperty };
foreach ( MyObject result in results ) { Console.WriteLine ( result ) ; }
変数result、c、resultsの型はすべて、最終的に使用されるメソッドのシグネチャに従ってコンパイラによって推論されます。メソッドの選択基準は、クエリ式フリーの翻訳 result によって形成されます。
IEnumerble < MyObject > results = SomeCollection.Where ( c = > c.SomeProperty < 10 ) .Select ( c = > new { c.SomeProperty , c.OtherProperty } ) ;
結果.ForEach ( x => { Console.WriteLine ( x.ToString ( ) ) ; } )
C#3.0仕様では、クエリ式パターンに加え、LINQ式からLINQ式を含まないC# 3.0のサブセットの式への変換規則が定義されています。このように定義された変換は実際には型指定されておらず、ラムダ式がデリゲートまたは式ツリーとして解釈可能であることに加え、インターフェースの一部をLINQ式句として公開したいライブラリにとって非常に柔軟な実装が可能になります。例えば、LINQ to ObjectsはIEnumerable<T>s とデリゲートで動作します
が、 LINQ to SQLは式ツリーを使用します。
式ツリーはLINQ拡張メカニズムの中核を成し、これによりLINQは様々なデータソースに適応できます。式ツリーはLINQプロバイダーに引き渡されます。LINQプロバイダーは、データソース固有の実装であり、データソースで使用できるようにLINQクエリを適応させます。LINQプロバイダーは、必要に応じてクエリに含まれる式ツリーを分析し、クエリの実行に必要な要素を生成します。これは、SQLフラグメントの場合もあれば、操作可能なデータとして表現された全く異なるコード形式である場合もあります。LINQには、メモリ内オブジェクトコレクション、Microsoft SQL Serverデータベース、ADO.NETデータセット、XMLドキュメント用のLINQプロバイダーが付属しています。これらの異なるプロバイダーは、LINQの異なるフレーバーを定義します。
LINQ to Objectsプロバイダーは、LINQのローカルクエリ実行エンジンを使用して、メモリ内コレクションに使用されます。このプロバイダーによって生成されるコードは、Sequenceパターンで定義されている標準クエリ演算子の実装を参照し、IEnumerable<T>コレクションをローカルでクエリできるようにします。LINQ to Objectsの現在の実装では、IEnumerableのランタイム型でサポートされている場合、インターフェイス実装チェックを実行して、メンバーシップテスト、カウント、インデックス付き検索操作を高速化します。[8] [9] [10]
LINQ to XMLプロバイダーはXML文書をXElementオブジェクトのコレクションに変換し、標準クエリ演算子の実装の一部として提供されるローカル実行エンジンを使用してクエリを実行します。[11]
LINQ to SQL プロバイダーを使用すると、LINQ を使用してMicrosoft SQL Serverデータベース(SQL Server Compactデータベースを含む)を照会できます。SQL Server のデータはリモート サーバーに存在する可能性があり、SQL Server には独自のクエリ エンジンがあるため、LINQ to SQL は LINQ のクエリ エンジンを使用しません。代わりに、LINQ クエリをSQLクエリに変換し、SQL Server に送信して処理します。[12]ただし、SQL Server はデータをリレーショナル データとして保存し、LINQ はオブジェクトにカプセル化されたデータを扱うため、この 2 つの表現を相互にマッピングする必要があります。このため、LINQ to SQL はマッピング フレームワークも定義しています。マッピングは、データベース内のテーブルに対応するクラスを定義し、テーブル内の列のすべてまたは一部をデータ メンバーとして含めることによって行われます。[13]この対応関係は、主キーなどの他のリレーショナル モデル属性とともに、LINQ to SQL 定義属性を使用して指定されます。たとえば、
[Table(Name="Customers")]
パブリッククラスCustomer { [Column(IsPrimaryKey = true)]パブリックint CustID ;
[列]
public string CustName ; }
このクラス定義は、という名前のテーブルにマッピングされCustomers、2つのデータメンバーは2つの列に対応しています。LINQ to SQLを使用する前に、これらのクラスを定義する必要があります。Visual Studio 2008には、オブジェクト内のデータスキーマとリレーショナルドメイン間のマッピングを作成できるマッピングデザイナーが含まれています。データベーススキーマから対応するクラスを自動的に作成できるだけでなく、テーブルまたはテーブル内の列のサブセットのみを使用して別のビューを作成するための手動編集も可能です。[13]
マッピングは、DataContextサーバーへの接続文字列を受け取る によって実装され、 を生成するために使用できます。Table<T>ここで、T はデータベーステーブルがマッピングされる型です。 はTable<T>テーブル内のデータをカプセル化し、IQueryable<T>インターフェイスを実装することで式ツリーを作成し、LINQ to SQL プロバイダーがこれを処理します。クエリをT-SQLに変換し、データベースサーバーから結果セットを取得します。処理はデータベースサーバーで行われるため、述語を表すラムダ式の一部として定義されていないローカルメソッドは使用できません。ただし、サーバー上のストアドプロシージャは使用できます。結果セットへの変更はすべて追跡され、データベースサーバーに返すことができます。[13]
LINQ to SQLプロバイダー(上記)はMicrosoft SQL Serverデータベースでのみ動作するため、あらゆる汎用データベースをサポートするために、LINQにはLINQ to DataSetsも含まれています。LINQ to DataSetsはADO.NETを使用してデータベースとの通信を処理します。データがADO.NET DataSetsに格納されると、LINQ to DataSetsはこれらのデータセットに対してクエリを実行します。[14]
非専門家ユーザーは、LINQ to Objectsの機能や構文の微妙な違いに苦労するかもしれません。単純なLINQの実装パターンは、パフォーマンスの壊滅的な低下につながる可能性があります。[15] [16]
LINQ to XMLとLINQ to SQLのパフォーマンスは、ADO.NETと比較してユースケースによって異なります。[17] [18]
.NET Framework バージョン4には、LINQクエリ用の並列実行エンジンであるPLINQ(Parallel LINQ)が含まれています 。これはクラスを定義しています。このインターフェースの実装は、.NET FrameworkのSystem.Linq名前空間にあるParallelEnumerableクラスで定義された拡張メソッドを呼び出すことで、PLINQエンジンを利用できます。[19] PLINQエンジンは、クエリの一部を複数のスレッドで同時に実行できるため、より高速な結果を得ることができます。[20]ParallelQuery<T>IEnumerable<T>AsParallel<T>(this IEnumerable<T>)
LINQが導入した概念の多くは、もともとMicrosoftのCω研究プロジェクトでテストされていました。このプロジェクトは、以前はX#(X Sharp)およびXenというコードネームで知られていました。Polyphonic C# (結合計算の原理に基づく別の研究言語)が統合された後、Cωに改名されました。
Cωは、データストア(データベースやXML文書など)を、文字列や配列といった従来の型と同じように簡単に型安全に利用できるようにすることを目指しています。これらのアイデアの多くは、WebData XMLチーム内の以前のインキュベーションプロジェクトであるX#とXenから継承されています。Cωには、並行プログラミングをサポートするための新しい構造も含まれています。これらの機能は、主に以前のPolyphonic C#プロジェクトから派生したものです。[21]
Cωの機能は2004年にコンパイラプレビューとして初めて利用可能になり、その後マイクロソフトは2007年に.NETバージョン3.5でリリースされたLINQ機能の作成に使用しました。[22]並行性構造は、 Microsoft ResearchによってC#やその他の.NET言語用のJoins Concurrency Libraryというライブラリとしてわずかに修正された形でリリースされました。[23]
LINQ のポートはPHP (PHPLinq Archived 2018-01-19 at the Wayback Machine )、JavaScript (linq.js)、TypeScript (linq.ts)、ActionScript (ActionLinq Archived 2018-12-25 at the Wayback Machine )、C++ (CXXIter ) 用に存在しますが、.NET に触発された言語である C#、F#、VB.NET の LINQ と厳密に同等のものはありません (これらの言語では LINQ は外部ライブラリではなく言語の一部であり、より幅広いニーズに対応します)。[引用が必要]
は強力で非常に効率的であることは事実ですが、大規模なデータセットは予期せぬパフォーマンスの問題を引き起こす可能性があります。
Frameworkでクエリを複数回呼び出す場合は、コンパイル済みLINQクエリを使用することをお勧めします。クエリをコンパイルすると、最初の使用時にはパフォーマンスが低下しますが、それ以降の呼び出しははるかに高速に実行されます。