LINQ to SQL では、グリッド コントロールなどの一般的なコントロールへのバインドがサポートされています。 具体的には、LINQ to SQL では、表示と更新の両方に関して、データ グリッドにバインドし、マスター/詳細バインディングを処理するための基本的なパターンを定義します。
本義
LINQ to SQL は、データベースで実行するために LINQ クエリを SQL に変換します。 その結果は、厳密に型指定された IEnumerable
になります。 これらのオブジェクトは通常の共通言語ランタイム (CLR) オブジェクトであるため、通常のオブジェクト データ バインディングを使用して結果を表示できます。 一方、変更操作 (挿入、更新、削除) には追加の手順が必要です。
オペレーション
Windows フォーム コントロールに暗黙的にバインドするには、 IListSourceを実装します。 データ ソースの汎用Table<TEntity> (C# または Visual Basic のTable<T>
でTable(Of T)
) と汎用DataQuery
が更新され、IListSourceが実装されました。 ユーザー インターフェイス (UI) データ バインディング エンジン (Windows フォームと Windows Presentation Foundation) の両方で、データ ソースが IListSource実装されているかどうかをテストします。 そのため、次の例のように、クエリの直接的な影響をコントロールのデータ ソースに書き込むと、LINQ to SQL コレクションの生成が暗黙的に呼び出されます。
DataGrid dataGrid1 = new DataGrid();
DataGrid dataGrid2 = new DataGrid();
DataGrid dataGrid3 = new DataGrid();
var custQuery =
from cust in db.Customers
select cust;
dataGrid1.DataSource = custQuery;
dataGrid2.DataSource = custQuery;
dataGrid2.DataMember = "Orders";
BindingSource bs = new BindingSource();
bs.DataSource = custQuery;
dataGrid3.DataSource = bs;
Dim dataGrid1 As New DataGrid()
Dim dataGrid2 As New DataGrid()
Dim dataGrid3 As New DataGrid()
Dim custQuery = _
From cust In db.Customers _
Select cust
dataGrid1.DataSource = custQuery
dataGrid2.DataSource = custQuery
dataGrid2.DataMember = "Orders"
Dim bs = _
New BindingSource()
bs.DataSource = custQuery
dataGrid3.DataSource = bs
Windows Presentation Foundation でも同様に発生します。
ListView listView1 = new ListView();
var custQuery2 =
from cust in db.Customers
select cust;
ListViewItem ItemsSource = new ListViewItem();
ItemsSource = (ListViewItem)custQuery2;
Dim listView1 As New ListView()
Dim custQuery2 = _
From cust In db.Customers _
Select cust
Dim ItemsSource As New ListViewItem
ItemsSource = custQuery2
コレクションの世代は、Table<TEntity>のジェネリック DataQuery
とジェネリック GetListによって実装されます。
IListSource の実装
LINQ to SQL では、次の 2 つの場所に IListSource が実装されます。
データ ソースは Table<TEntity>です。LINQ to SQL はテーブルを参照して、テーブルへの参照を保持する
DataBindingList
コレクションを格納します。データ ソースは IQueryable<T>です。 次の 2 つのシナリオがあります。
LINQ to SQL がTable<TEntity>から基になるIQueryable<T>を見つけた場合、ソースはエディションを許可し、状況は最初の箇条書きと同じです。
基になる Table<TEntity>が LINQ to SQL で見つからない場合、ソースではエディション (
groupby
など) は許可されません。 LINQ to SQL は、クエリを参照して汎用SortableBindingList
を入力します。これは、特定のプロパティの T エンティティの並べ替え機能を実装する単純な BindingList<T> です。
特殊なコレクション
このドキュメントで既に説明した多くの機能について、 BindingList<T> はいくつかの異なるクラスに特化されています。 これらのクラスは、ジェネリック SortableBindingList
およびジェネリック DataBindingList
です。 どちらも内部として宣言されています。
ジェネリック SortableBindingList
このクラスは BindingList<T>から継承され、 BindingList<T>の並べ替え可能なバージョンです。 並べ替えはメモリ内ソリューションであり、データベース自体に接触することはありません。
BindingList<T> は IBindingList を実装しますが、既定では並べ替えをサポートしていません。 ただし、BindingList<T>は仮想IBindingList メソッドを使用してを実装します。 これらのメソッドは簡単にオーバーライドできます。 汎用 SortableBindingList
は、 SupportsSortingCore、 SortPropertyCore、 SortDirectionCore、および ApplySortCoreをオーバーライドします。
ApplySortCore
は ApplySort によって呼び出され、特定のプロパティの T 項目の一覧を並べ替えます。
プロパティが T に属していない場合、例外が発生します。
並べ替えを実現するために、LINQ to SQL はジェネリック SortableBindingList.PropertyComparer
から継承するジェネリック IComparer.Compare クラスを作成し、特定の型 T、PropertyDescriptor
、および方向の既定の比較子を実装します。 このクラスは、T がComparer
のPropertyType
である T のPropertyDescriptor
を動的に作成します。 次に、既定の比較子が静的ジェネリック Comparer
から取得されます。 既定のインスタンスは、リフレクションを使用して取得されます。
ジェネリック SortableBindingList
は、 DataBindingList
の基本クラスでもあります。 汎用 SortableBindingList
には、追跡を追加または削除する項目を中断または再開するための 2 つの仮想メソッドが用意されています。 これら 2 つのメソッドは、並べ替えなどの基本機能に使用できますが、実際にはジェネリック DataBindingList
などの上位クラスによって実装されます。
ジェネリックデータバインディングリスト
このクラスは、ジェネリック SortableBindingLIst
から継承されます。 ジェネリック DataBindingList
は、コレクションの初期入力に使用されるジェネリック Table
の基になるジェネリック IQueryable
への参照を保持します。 ジェネリック DatabindingList
は、 InsertItem
() と RemoveItem
() をオーバーライドすることで、アイテムの追加/削除の追跡をコレクションに追加します。 また、追跡を条件付きにするために、抽象中断/再開追跡機能も実装します。 この機能により、一般的な DataBindingList
は、親クラスの追跡機能のすべてのポリモーフィックな使用法を利用できます。
EntitySets へのバインド
EntitySet
は既にEntitySet
を実装するコレクションであるため、IBindingListへのバインドは特殊なケースです。 LINQ to SQL では、並べ替えと取り消し (ICancelAddNew) のサポートが追加されました。
EntitySet
クラスは、内部リストを使用してエンティティを格納します。 このリストは、ジェネリック配列 (ジェネリック ItemList
クラス) に基づく下位レベルのコレクションです。
並べ替え機能の追加
配列には、T のArray.Sort()
で使用できる並べ替えメソッド (Comparer
) が用意されています。LINQ to SQL では、このトピックで前述したジェネリック SortableBindingList.PropertyComparer
クラスを使用して、プロパティと並べ替える方向のこのComparer
を取得します。 この機能を呼び出すために、 ApplySort
メソッドが汎用 ItemList
に追加されます。
EntitySet
側で、並べ替えのサポートを宣言する必要があります。
SupportsSorting は、
true
を返します。ApplySort は
entities.ApplySort()
を呼び出してからOnListChanged()
します。SortDirection プロパティと SortProperty プロパティは、ローカル メンバーに格納されている現在の並べ替え定義を公開します。
System.Windows.Forms.BindingSource を使用して EntitySet<TEntity> を System.Windows.Forms.BindingSource.DataSource にバインドする場合は、BindingSource.List を更新するために EntitySet<TEntity>.GetNewBindingList を呼び出す必要があります。
System.Windows.Forms.BindingSource を使用し、BindingSource.DataMember プロパティを設定し、BindingSource.DataMember で EntitySet<TEntity> を公開するプロパティを持つクラスに BindingSource.DataSource を設定する場合は、EntitySet<TEntity> を呼び出す必要はありません。GetNewBindingList を使用して BindingSource.List を更新しますが、並べ替え機能が失われます。
キャッシュ処理
LINQ to SQL クエリは、 GetListを実装します。 Windows フォーム BindingSource クラスがこのインターフェイスを満たすと、1 つの接続に対して GetList() が 3 回呼び出されます。 この状況を回避するために、LINQ to SQL はインスタンスごとにキャッシュを実装して格納し、常に同じ生成されたコレクションを返します。
キャンセル
IBindingList は、バインドされたコレクションから新しい項目を作成するためにコントロールによって使用される AddNew メソッドを定義します。
DataGridView
コントロールは、最後に表示される行のヘッダーに星が含まれている場合に、この機能を非常によく示します。 星には、新しい項目を追加できることを示します。
この機能に加えて、コレクションは ICancelAddNewを実装することもできます。 この機能を使用すると、コントロールは、新しい編集済みアイテムが検証されたかどうかをキャンセルまたは検証できます。
ICancelAddNew は、すべての LINQ to SQL データバインド コレクション (ジェネリック SortableBindingList
およびジェネリック EntitySet
) に実装されます。 どちらの実装でも、コードは次のように実行されます。
項目を挿入し、コレクションから削除できるようにします。
UI がエディションをコミットしない限り、変更を追跡しません。
エディションが取り消された (CancelNew) 限り、変更を追跡しません。
エディションがコミットされたときの追跡を許可します (EndNew)。
新しい項目が AddNewから取得されていない場合は、コレクションが正常に動作できるようにします。
トラブルシューティング
このセクションでは、LINQ to SQL データ バインディング アプリケーションのトラブルシューティングに役立つ可能性のあるいくつかの項目について説明します。
プロパティを使用する必要があります。フィールドのみを使用するだけでは不十分です。 Windows フォームでは、この使用法が必要です。
既定では、
image
、varbinary
、およびtimestamp
データベース型はバイト配列にマップされます。 このシナリオではToString()
はサポートされていないため、これらのオブジェクトを表示できません。主キーにマップされたクラス メンバーにはセッターがありますが、LINQ to SQL ではオブジェクト ID の変更はサポートされていません。 そのため、マッピングで使用される主キーまたは一意キーをデータベースで更新することはできません。 グリッドを変更すると、 SubmitChangesを呼び出すと例外が発生します。
エンティティが 2 つの独立したグリッド (マスターグリッドと別の詳細グリッドなど) にバインドされている場合、マスター グリッド内の
Delete
は詳細グリッドに反映されません。