共用方式為


資料繫結

LINQ to SQL 支援通用控制項,例如格線控制項。 具體來說,LINQ to SQL 會定義資料格繫結與主要-詳細資料繫結處理的基本模式,而這兩者都與顯示和更新相關。

基礎準則

LINQ to SQL 會將 LINQ 查詢轉譯為 SQL,以在資料庫中執行。 而產生的結果會是強型別 (Strongly Typed) IEnumerable。 因為這些物件是一般 Common Language Runtime (CLR) 物件,所以一般物件資料繫結 (Data Binding) 可以用來顯示結果。 另一方面,變更作業 (插入、更新和刪除) 則需要額外的步驟。

作業

實作 IListSource,就可以隱含地繫結至 Windows Forms 控制項。 資料來源泛型 Table<TEntity> (在 C# 中為 Table<T>,或在 Visual Basic 中為 Table(Of T)),以及泛型 DataQuery 已更新為實作 IListSource。 使用者介面 (UI) 資料繫結引擎 (Windows Form 和 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 會在兩個位置實作 IListSource

  • 若資料來源為 Table<TEntity>:LINQ to SQL 會瀏覽資料表,以填入 DataBindingList 集合,此集合會將參考保留在資料表上。

  • 資料來源是 IQueryable<T>。 有兩種案例:

    • 若 LINQ to SQL 從 IQueryable<T> 找到基礎 Table<TEntity>,則允許編輯來源,且狀況會與第一點所述相同。

    • 若 LINQ to SQL 找不到基礎 Table<TEntity>,則不允許編輯來源 (例如 groupby)。 LINQ to SQL 會瀏覽查詢,以填入泛型 SortableBindingList,此為簡單的 BindingList<T>,可針對指定屬性實作 T 實體的排序功能。

特定的集合

BindingList<T> 已針對本文件之前描述的許多功能,特殊化為一些不同類別。 這些類別是泛型 SortableBindingList 和泛型 DataBindingList。 這兩種類別都是宣告為內部。

泛型 SortableBindingList

這個類別繼承自 BindingList<T>,而且是 BindingList<T> 的可排序版本。 排序動作僅在記憶體中執行,並不會連絡資料庫本身。 BindingList<T> 會實作 IBindingList,但是預設不支援排序。 不過 BindingList<T> 會使用虛擬 core 方法實作 IBindingList。 您可以輕鬆地覆寫這些方法。 泛型 SortableBindingList 會覆寫 SupportsSortingCoreSortPropertyCoreSortDirectionCoreApplySortCoreApplySortCore 是透過 ApplySort 進行呼叫,而且會排序所指定屬性的 T 項目清單。

如果屬性不屬於 T,則會引發例外狀況 (Exception)。

為了進行排序,LINQ to SQL 會建立繼承自泛型 IComparer.Compare 的泛型 SortableBindingList.PropertyComparer 類別,並實作所指定類型 T 的預設比較子、PropertyDescriptor 以及方向。 這個類別會動態建立 T 的 Comparer,其中 T 是 PropertyTypePropertyDescriptor。 然後,會從靜態泛型 Comparer 中擷取預設比較子。 而預設執行個體是使用反映 (Reflection) 取得。

泛型 SortableBindingList 也是 DataBindingList 的基底類別。 泛型 SortableBindingList 提供兩種虛擬方法,以暫止或繼續項目的新增/移除追蹤 (Tracking)。 這兩種方法都適用於排序這類的基本功能,但是會由泛型 DataBindingList 這類的上層類別實際實作。

泛型 DataBindingList

這個類別繼承自泛型 SortableBindingLIst。 泛型 DataBindingList 會保存對泛型 Table 之基礎泛型 IQueryable (用於初始填入集合) 的參考。 泛型 DatabindingList 會覆寫 InsertItem() 和 RemoveItem(),以將項目新增/移除的追蹤加入至集合。 也會實作抽象的暫止/繼續追蹤功能,讓追蹤具有條件性。 這個功能可以讓泛型 DataBindingList 利用父類別之追蹤功能的所有多型使用。

繫結至 EntitySet

因為 EntitySet 已經是實作 EntitySet 的集合,所以繫結至 IBindingList 是特殊情況。 LINQ to SQL 加入了排序和取消 (ICancelAddNew) 支援。 EntitySet 類別會使用內部清單來儲存實體。 這份清單是以泛型陣列 (泛型 ItemList 類別) 為基礎的低階集合。

加入排序功能

陣列提供的排序方法 (Array.Sort())可與 T 的 Comparer 搭配使用。LINQ to SQL 會使用本主題先前所述的泛型 SortableBindingList.PropertyComparer 類別,取得屬性的這個 Comparer 以及排序方向。 ApplySort 方法會加入至泛型 ItemList,以呼叫這個功能。

您現在必須在 EntitySet 端上宣告排序支援:

當您使用 System.Windows.Forms.BindingSource 並將 EntitySet<TEntity> 繫結至 System.Windows.Forms.BindingSource.DataSource 時,必須呼叫 EntitySet<TEntity>.GetNewBindingList 以更新 BindingSource.List。

若您使用 System.Windows.Forms.BindingSource 並設定 BindingSource.DataMember 屬性,且將 BindingSource.DataSource 設定為在公開 EntitySet<TEntity> 的 BindingSource.DataMember 中命名之屬性的所屬類別, 則無須呼叫 EntitySet<TEntity>.GetNewBindingList 來更新 BindingSource.List,但您會失去排序功能。

快取功能

LINQ to SQL 查詢會實作 GetList。 Windows Forms BindingSource 類別符合這個介面時,會針對單一連接呼叫三次 GetList()。 為了解決此情況,LINQ to SQL 會對每個執行個體實作快取,以儲存並一律傳回相同的產生集合。

取消

IBindingList 定義 AddNew 方法,讓控制項用來從繫結集合建立新項目。 DataGridView 控制項會在最後一個可見資料列的標頭顯示星號,能充分地呈現這個功能特徵。 星號表示您可以加入新的項目。

除了這個功能之外,集合也可以實作 ICancelAddNew。 這個功能允許控制項取消或驗證是否已驗證過新的編輯過項目。

ICancelAddNew 會實作於所有 LINQ to SQL 資料繫結集合 (泛型 SortableBindingList 和泛型 EntitySet)。 在這兩個實作中,程式碼執行如下:

  • 允許項目插入後又從集合中移除。

  • 只要 UI 未認可編輯,就不追蹤變更。

  • 只要取消編輯,就不追蹤變更 (CancelNew)。

  • 允許在認可編輯時進行追蹤 (EndNew)。

  • 如果新項目不是來自 AddNew,則讓集合正常運作。

疑難排解

此區段會提供數個項目,可能有助於排解 LINQ to SQL 資料繫結應用的問題。

  • 您必須使用屬性,只使用欄位是不夠的。 Windows Forms 需要這種使用方式。

  • 根據預設,imagevarbinarytimestamp 資料庫類型會對應至位元組陣列。 因為此案例不支援 ToString(),所以無法顯示這些物件。

  • 對應至主索引鍵的類別成員會有 setter,但 LINQ to SQL 不支援變更物件身分識別。 因此,無法更新資料庫中用於對應的主/唯一索引鍵。 當您呼叫 SubmitChanges 時,格線變更會導致例外狀況發生。

  • 如果實體是繫結在兩個不同方格中 (例如,一個是主版方格,而另一個詳細方格),則主版方格中的 Delete 不會散佈至詳細方格。

另請參閱