言語統合クエリ(LINQ、発音は「リンク」)は、.NET言語にネイティブなデータクエリ機能を追加するMicrosoft .NETフレームワークのコンポーネントであり、元々は2007年に.NET Framework 3.5の主要機能としてリリースされました。
LINQ は、 SQLステートメントに似たクエリ式を追加することで言語を拡張し、配列、列挙可能なクラス、XMLドキュメント、リレーショナル データベース、サードパーティ データ ソースからデータを便利に抽出および処理するために使用できます。クエリ式を任意の計算を読みやすく構成するための一般的なフレームワークとして利用するその他の用途には、イベント ハンドラー[ 1 ]やモナドパーサー[ 2 ]の構築などがあります。また、一連のメソッド名 (標準クエリ演算子または標準シーケンス演算子と呼ばれる) と、コンパイラがクエリ構文式をこれらのメソッド名、ラムダ式、匿名型を使用した流暢なスタイル(Microsoft ではメソッド構文と呼ばれる) の式に変換するために使用する変換ルールも定義しています。
以下では、演算子の説明はコレクションの操作を前提としています。多くの演算子は、引数として他の関数を受け取ります。これらの関数は、名前付きメソッドまたは匿名関数の形式で指定できます。
LINQ で定義されているクエリ演算子のセットは、標準クエリ演算子 (SQO) アプリケーション プログラミング インターフェイス ( API )としてユーザーに公開されます。API でサポートされているクエリ演算子は次のとおりです。[ 3 ]
SelectこのSelect演算子は、コレクションに対して射影を行い、要素の興味深い側面を選択します。ユーザーは、データメンバーを射影する任意の関数を、名前付き式またはラムダ式の形式で指定します。この関数は、デリゲートとして演算子に渡されます。これにより、Map高階関数が実装されます。
WhereWhereこの演算子を使用すると、コレクション内の各オブジェクトに対して評価される述語ルールのセットを定義できます。ルールに一致しないオブジェクトは除外されます。述語はデリゲートとして演算子に渡されます。これは、高階関数である Filter を実装したものです。
SelectManyユーザーが指定したコレクション要素からコレクションへのマッピングの場合、意味的には 2 つのステップが実行されます。まず、各要素が対応するコレクションにマッピングされます。次に、最初のステップの結果が 1 レベルでフラット化されます。Selectと は、シングルトンおよび空のコレクションが利用可能である限り、Whereの観点から実装可能ですSelectMany。上記の変換ルールにより、LINQ プロバイダは他の 2 つの演算子を提供することが必須となります。これは、Bind高階関数を実装します。
Sum、、、MinMaxAverageこれらの演算子は、オプションで、コレクション内の各要素から特定の数値を取得し、それを用いてコレクション内のすべての要素の合計、最小値、最大値、または平均値をそれぞれ求める関数を受け取ります。オーバーロードされたバージョンは関数を受け取らず、ラムダ式として恒等式が与えられたかのように動作します。
Aggregate一般化されたSum/ Min/Max演算子。この演算子は、2 つの値を組み合わせて中間結果または最終結果を生成する方法を指定する関数を受け取ります。オプションで開始値を指定することで、集計結果の型を任意にすることができます。さらに、集計結果を別の値に変換する最終化関数を指定することもできます。これは、高階関数Foldを実装したものです。
Join、GroupJoinこのJoin演算子は、各コレクション内のオブジェクトのキーの一致に基づいて、2 つのコレクションに対して内部結合を実行します。各コレクションごとに 1 つの関数をデリゲートとして受け取り、コレクション内の各オブジェクトに対してその関数を実行して、オブジェクトからキーを抽出します。また、ユーザーが一致した 2 つの要素から、結果のオブジェクトを作成するために使用するデータ要素を指定する別のデリゲートも受け取ります。この演算子はグループ結合をGroupJoin実行します。この演算子と同様に、結合の結果は、ソース オブジェクトの両方のタイプのすべてのデータ メンバー、またはそのサブセットを持つ、別のクラスのインスタンスになります。Select
Take、TakeWhile演算子はコレクションからTake最初のオブジェクトを選択しますが、述語を受け取る演算子は、述語に一致するオブジェクトを選択します(一致しない最初のオブジェクトで停止します)。nTakeWhile
Skip、SkipWhileおよび演算子はSkip、およびSkipWhileの補数です。コレクションの最初のオブジェクト、または述語に一致するオブジェクト(の場合)をスキップします。TakeTakeWhilenSkipWhile
OfTypeこのOfType演算子は、特定の種類の要素を選択するために使用されます。
ConcatこのConcat演算子は2つのコレクションを連結します。
OrderBy、ThenByこのOrderBy演算子は、コレクション内の要素をキーに基づいて優先的にソートする順序を指定するために使用されます。デフォルトの順序は昇順です。順序を反転するには、このOrderByDescending演算子を使用します。ThenByまた、ThenByDescendingこの演算子は要素のその後の順序を指定します。オブジェクトからキー値を抽出する関数は、ユーザーがデリゲートとして指定します。
ReverseこのReverse演算子はコレクションを反転させます。
GroupByこの演算子は、キー値を抽出する関数を受け取り、各キー値ごとにオブジェクトGroupByのコレクションを返します。これらのオブジェクトを使用して、特定のキー値に対応するすべてのオブジェクトを列挙できます。System.Linq.IGrouping<K, V>System.Linq.IGrouping<K, V>
DistinctこのDistinct演算子は、コレクションからオブジェクトの重複インスタンスを削除します。この演算子のオーバーロードでは、重複の有無の基準を定義する等価比較オブジェクトを受け取ります。
Union、、IntersectExceptこれらの演算子は、それぞれ2つのシーケンスに対して和集合、積集合、差集合の演算を実行するために使用されます。各演算子には、要素の等価性の基準を定義する等価比較オブジェクトを受け取るオーバーロードがあります。
SequenceEqualこのSequenceEqual演算子は、2つのコレクション内のすべての要素が等しく、かつ同じ順序であるかどうかを判定します。
First、、、FirstOrDefaultLastLastOrDefaultこれらの演算子は述語を受け取ります。First演算子は、述語が真となる最初の要素を返します。一致する要素がない場合は例外をスローします。演算子は、述語に一致する要素がない場合に要素型のデフォルト値(通常はnull 参照FirstOrDefault)を返す点を除いて、演算子と似ています。演算子は、述語に一致する最後の要素を取得します。一致する要素がない場合は、例外をスローします。一致する要素がない場合は、デフォルトの要素値を返します。FirstLastLastOrDefault
Single、SingleOrDefaultこのSingle演算子は述語を受け取り、その述語に一致する要素を返します。述語に一致する要素が一つもない場合、または複数の要素が一致する場合は、例外がスローされます。
このSingleOrDefault演算子は述語を受け取り、その述語に一致する要素を返します。述語に一致する要素が複数ある場合は、例外がスローされます。述語に一致する要素がない場合は、デフォルト値が返されます。
ElementAtこのElementAt演算子は、コレクション内の指定されたインデックスにある要素を取得します。
Any、AllこのAny演算子は、コレクション内に述語に一致する要素が存在するかどうかを確認します。要素を選択するのではなく、少なくとも1つの要素が一致した場合にtrueを返します。述語を指定せずにanyを呼び出すと、コレクションが空でない場合はtrueを返します。Allすべての要素が述語に一致する場合は、この演算子はtrueを返します。
ContainsこのContains演算子は、コレクションに指定された要素が含まれているかどうかを確認します。
CountこのCount演算子は、指定されたコレクション内の要素数をカウントします。述語を受け取るオーバーロードは、その述語に一致する要素数をカウントします。
標準クエリ演算子APIでは、コレクションを別の型に変換する特定の演算子も規定されています。[ 3 ]
AsEnumerable: コレクションを静的に型付けしますSystem.Collections.Generic.IEnumerable<T>。[ 4 ]AsQueryable: コレクションを静的に型付けしますSystem.Linq.IQueryable<T>。ToArrayT[]:コレクションから配列を作成します。ToList:System.Collections.Generic.List<T>コレクションからを作成します。ToDictionary:System.Collections.Generic.Dictionary<K, V>コレクションからキーでインデックス付けされたを作成しますK。ユーザーが指定した射影関数が、各要素からキーを抽出します。ToLookup:System.Linq.Lookup<K, V>コレクションからキーでインデックス付けされたを作成しますK。ユーザーが指定した射影関数が、各要素からキーを抽出します。Cast: 非ジェネリックコレクションを、各要素を型にキャストすることで、System.Collections.IEnumerableいずれかの型に変換します。 または、ジェネリックを別のジェネリックに変換するために、各要素を型から型にキャストします。 要素を指定された型にキャストできない場合は、例外をスローします。System.Collections.Generic.IEnumerable<T>TSystem.Collections.Generic.IEnumerable<T>System.Collections.Generic.IEnumerable<R>TROfType: 非ジェネリックSystem.Collections.IEnumerableコレクションを のいずれかに変換します。または、各要素を 型から型にキャストすることで、System.Collections.Generic.IEnumerable<T>ジェネリックSystem.Collections.Generic.IEnumerable<T>を別のジェネリックに変換します。どちらの場合も、ターゲット型に正常にキャストされた要素のサブセットのみが含まれます。例外はスローされません。System.Collections.Generic.IEnumerable<R>TRLINQ は主に.NET Framework 3.5 のライブラリとして実装されていますが、クエリを第一級の言語構造にし、クエリを記述するための構文糖衣を提供するオプションの言語拡張機能も定義しています。これらの言語拡張機能は、当初C# 3.0 [ 5 ] : 75 VB 9.0、F# [ 6 ]およびOxygeneで実装され、 Nemerleなどの他の言語も 予備的なサポートを発表しています。言語拡張機能には以下が含まれます。[ 7 ]
var、キーワードを使用して宣言します。VB9.0 では、Dim型宣言なしのキーワードで同じことができます。このようなオブジェクトは依然として厳密に型付けされています。これらのオブジェクトの場合、コンパイラは型推論によって変数の型を推論するため、中間変数の型を宣言せずにクエリの結果を指定および定義できます。例えば、コレクション内のオブジェクトをSomeProperty10個未満選択するクエリでは、
using System ; using System.Collections.Generic ;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、最終的に使用されるメソッドのシグネチャに従ってコンパイラによって推論されます。メソッドを選択するための基準は、クエリ式を含まない変換結果によって形成されます。cresults
using System ; using System.Collections.Generic ;IEnumerable <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 はSystem.Collections.Generic.IEnumerable<T>オブジェクトとデリゲートで動作します が、 LINQ to SQL は式ツリーを使用します。
式ツリーは、LINQ の拡張メカニズムの中核を成すものであり、LINQ をさまざまなデータソースに適合させることができます。式ツリーは LINQ プロバイダに渡されます。LINQ プロバイダは、データソース固有の実装であり、LINQ クエリをデータソースに合わせて調整します。LINQ プロバイダは、必要に応じて、クエリに含まれる式ツリーを分析し、クエリの実行に必要な要素を生成します。これは、SQL フラグメントであったり、さらに操作可能なデータとして、コードのまったく異なる表現形式であったりします。LINQ には、インメモリオブジェクトコレクション、Microsoft SQL Serverデータベース、ADO.NETデータセット、および XML ドキュメント用の LINQ プロバイダが付属しています。これらの異なるプロバイダによって、LINQ のさまざまな種類が定義されます。
LINQ to Objects プロバイダーは、LINQ のローカル クエリ実行エンジンを使用して、メモリ内のコレクションに使用されます。このプロバイダーによって生成されるコードは、Sequenceパターンで定義されている標準クエリ演算子の実装を参照し、System.Collections.Generic.IEnumerable<T>コレクションをローカルでクエリできるようにします。現在の LINQ to Objects の実装では、インターフェースの実装チェックを実行して、ランタイム タイプのサポートがある場合に、メンバーシップ テスト、カウント、およびインデックス付きルックアップ操作を高速に実行できるようにしますSystem.Collections.Generic.IEnumerable<T>。[ 8 ] [ 9 ] [ 10 ]
LINQ to XML プロバイダーは、XML ドキュメントをSystem.Linq.Xml.XElementオブジェクトのコレクションに変換し、標準クエリ演算子の実装の一部として提供されるローカル実行エンジンを使用してクエリを実行します。[ 11 ] LINQ to XML プロバイダーは、XML ドキュメントをSystem.Linq.Xml.XElementオブジェクトのコレクションに変換し、標準クエリ演算子の実装の一部として提供されるローカル実行エンジンを使用してクエリを実行します。[ 12 ]
LINQ to SQL プロバイダーを使用すると、LINQ を使用してMicrosoft SQL Serverデータベース ( SQL Server Compactデータベースを含む) をクエリできます。SQL Server データはリモート サーバーに存在する可能性があり、SQL Server には独自のクエリ エンジンがあるため、LINQ to SQL は LINQ のクエリ エンジンを使用しません。代わりに、LINQ クエリをSQLクエリに変換し、それを SQL Server に送信して処理します。[ 13 ]ただし、SQL Server はデータをリレーショナル データとして格納し、LINQ はオブジェクトにカプセル化されたデータを扱うため、2 つの表現を相互にマッピングする必要があります。このため、LINQ to SQL はマッピング フレームワークも定義しています。マッピングは、データベース内のテーブルに対応するクラスを定義し、テーブル内のすべての列または一部の列をデータ メンバーとして含めることによって行われます。[ 14 ]対応関係は、主キーなどの他のリレーショナル モデル属性とともに、LINQ to SQL で定義された属性を使用して指定されます。たとえば、
System.Data.Linqを使用します。[Table(Name="Customers")] public class Customer { [Column(IsPrimaryKey = true)] public int CustID ;[Column] public string CustName ; }このクラス定義は、という名前のテーブルにマッピングされCustomers、2 つのデータ メンバーは 2 つの列に対応します。LINQ to SQL を使用する前に、クラスを定義する必要があります。Visual Studio 2008には、オブジェクトのデータ スキーマとリレーショナル ドメイン間のマッピングを作成するために使用できるマッピング デザイナーが含まれています。データベース スキーマから対応するクラスを自動的に作成できるほか、テーブルまたはテーブル内の列のサブセットのみを使用して別のビューを作成するための手動編集も可能です。[ 14 ]
マッピングはSystem.Data.Linq.DataContext、サーバーへの接続文字列を受け取るによって実装され、データベース テーブルがマッピングされる型でSystem.Data.Linq.Table<T>あるを生成するために使用できます。 はテーブル内のデータをカプセル化し、インターフェイスを実装して、LINQ to SQL プロバイダーが処理する式ツリーを作成します。クエリをT-SQLに変換し、データベース サーバーから結果セットを取得します。処理はデータベース サーバーで行われるため、述語を表すラムダ式の一部として定義されていないローカル メソッドは使用できません。ただし、サーバー上のストアド プロシージャを使用できます。結果セットへの変更は追跡され、データベース サーバーに送信できます。[ 14 ]TSystem.Data.Linq.Table<T>System.Linq.IQueryable<T>
上記の LINQ to SQL プロバイダーはMicrosoft SQL Serverデータベースでのみ動作するため、汎用データベースをサポートするために、LINQ には LINQ to DataSets も含まれています。これは ADO.NET を使用してデータベースとの通信を処理します。データが ADO.NET DataSets に格納されると、LINQ to DataSets はこれらのデータセットに対してクエリを実行します。[ 15 ]
非専門家ユーザーは、LINQ to Objects の機能や構文の微妙な点に苦労する可能性があります。単純な LINQ の実装パターンは、パフォーマンスの壊滅的な低下につながる可能性があります。[ 16 ] [ 17 ]
LINQ to XMLとLINQ to SQL のパフォーマンスは、ADO.NET と比較して、ユースケースによって異なります。[ 18 ] [ 19 ]
.NET Framework バージョン 4 には、 LINQ クエリの並列実行エンジンであるParallel Extensions for Parallel LINQ (PLINQ)が含まれています。これはクラスを定義します。インターフェイスの実装は、.NET Framework のクラス名前空間で定義されている拡張メソッドを呼び出すことで、PLINQ エンジンを利用できます。 [ 20 ] PLINQ エンジンは、クエリの一部を複数のスレッドで同時に実行できるため、より高速な結果が得られます。[ 21 ]System.Linq.ParallelQuery<T>System.Collections.Generic.IEnumerable<T>AsParallel<T>(thisIEnumerable<T>)System.Linq.ParallelEnumerable
LINQで導入された概念の多くは、もともとMicrosoftのCω研究プロジェクト(以前はX#(Xシャープ)やXenというコードネームで知られていた)でテストされたものでした。結合計算の原理に基づいた別の研究言語であるポリフォニックC#が統合された後、Cωと改名されました。
Cω は、データベースやXMLドキュメントなどのデータストアを、文字列や配列などの従来の型と同じ容易さと型安全性でアクセスできるようにすることを目指しています。これらのアイデアの多くは、WebData XML チーム内の以前のインキュベーション プロジェクトである X# および Xen から受け継がれています。Cω には、並行プログラミングをサポートする新しい構造も含まれています。これらの機能は、以前の Polyphonic C# プロジェクトから主に派生したものです。[ 22 ]
2004年にコンパイラのプレビューとして初めて公開されたCωの機能は、その後Microsoftによって.NETバージョン3.5で2007年にリリースされたLINQ機能の作成に使用されました[ 23 ]。並行処理の構成要素は、 Microsoft ResearchによってC#やその他の.NET言語用のJoins Concurrency Libraryというライブラリとして、若干修正された形でもリリースされています[ 24 ]。
{{cite web}}: CS1メンテナンス: アーカイブサービスは非推奨になりました (リンク){{cite web}}: CS1メンテナンス: アーカイブサービスは非推奨になりました (リンク)確かにLINQは強力で非常に効率的ですが、大規模なデータセットでは予期せぬパフォーマンスの問題が発生する可能性があります。
Entity Frameworkでクエリを複数回呼び出す場合、コンパイル済みLINQクエリを使用することをお勧めします。クエリをコンパイルすると、最初にクエリを使用するときにパフォーマンスが低下しますが、その後の呼び出しははるかに高速に実行されます。