.NET Framework 開發的階層式更新

注意

資料集和相關類別是 2000 年代初的舊版 .NET Framework 技術,可讓應用程式在應用程式與資料庫中斷連線時使用記憶體中的資料。 它們特別適用於可讓使用者修改資料並將變更保存回資料庫的應用程式。 雖然已證明資料集是非常成功的技術,但建議新的 .NET 應用程式使用 Entity Framework Core。 Entity Framework 提供更自然的方式,將表格式資料作為物件模型使用,而且具有更簡單的程式設計介面。

階層式更新 是指將更新的資料 (從具有兩個或多個相關資料表的資料集) 儲存回資料庫,同時維護參考完整性規則的流程。 參考完整性 是指資料庫中限制式所提供的一致性規則,以控制插入、更新和刪除相關記錄的行為。 例如,在允許為該客戶建立訂單之前,強制建立客戶記錄的參考完整性。 如需資料集中關聯性的資訊,請參閱 作法: 資料庫的關聯性

階層式更新功能會使用 TableAdapterManager 來管理具型別資料集中的 TableAdapterTableAdapterManager 元件是 Visual Studio 產生的類別,而不是 .NET 類型。 當您將資料表從 資料來源 視窗拖曳至 Windows Form 或 WPF 頁面時,Visual Studio 會將 TableAdapterManager 類型的變數新增至表單或頁面,並在元件匣的設計工具中看到該變數。 如需 TableAdapterManager 類別的詳細資訊,請參閱 TableAdapters的 TableAdapterManager 參考章節。

根據預設,資料集會將相關資料表視為「僅關聯」,這表示它不會強制執行外部索引鍵條件約束。 您可以使用 資料集設計工具,在設計階段修改該設定。 選取兩個資料表之間的關聯線,以顯示 [關聯] 對話方塊。 您在這裡所做的變更會決定當 TableAdapterManager 將相關資料表中的變更傳送回資料庫時的行為。

在資料集中啟用階層式更新

根據預設,會針對在專案中新增或建立的所有新資料集啟用階層式更新。 將資料集中具型別的資料集 階層式更新 屬性設定為 [True][False],以開啟或關閉階層式更新:

階層式更新設定

若要建立資料表之間的新關聯性

若要在兩個資料表之間建立新關聯性,請在資料集設計工具中選取每個資料表的標題列,然後按一下滑鼠右鍵,然後選取 [新增關聯]

階層式更新新增關聯功能表

了解外部索引鍵條件約束、串聯更新和刪除

請務必了解在產生的資料集程式碼中,如何建立資料庫中的外部索引鍵條件約束和串聯行為。

根據預設,資料集中的資料表會產生與資料庫中關聯性相符的關聯性 (DataRelation)。 不過,資料集中的關聯性不會產生為外部索引鍵條件約束。 DataRelation 已設定為 只有關聯,而沒有 UpdateRuleDeleteRule 生效。

根據預設,即使資料庫關聯圖是以串聯更新設定,或者串聯刪除已開啟,仍會關閉串聯更新和串聯刪除。 例如,建立新的客戶和新訂單,然後嘗試儲存資料可能會導致與資料庫中定義的外部索引鍵條件約束產生衝突。 如需詳細資訊,請參閱 在填寫資料集時關閉條件約束

設定執行更新的順序

設定執行更新的順序會設定個別插入、更新和刪除的順序,這些插入、更新和刪除是儲存資料集所有資料表中所有修改過的資料所需的順序。 啟用階層式更新時,會先執行插入、更新,然後再刪除。 TableAdapterManager 提供可設定為先執行更新的 UpdateOrder 屬性,然後插入,然後刪除。

注意

請務必了解更新順序為全包。 也就是說,執行更新時,會針對資料集中的所有資料表執行插入和刪除。

若要設定 UpdateOrder 屬性,將項目從 資料來源 視窗拖曳到表單上之後,請選取元件匣中的 TableAdapterManager ,然後在 [屬性] 視窗中設定 UpdateOrder 屬性。

在執行階層式更新之前,先建立資料集的備份複本

當您儲存資料時 (藉由呼叫 TableAdapterManager.UpdateAll() 方法),TableAdapterManager 會嘗試在單一交易中更新每個資料表的資料。 如果任何資料表的任何更新部分失敗,則會復原整個交易。 在大部分情況下,復原會將您的應用程式傳回其原始狀態。

不過,有時候您可能會想要從備份複本還原資料集。 其中一個範例是當您使用自動遞增值時。 例如,如果儲存作業不成功,則資料集不會重設自動遞增值,而且資料集會繼續建立自動遞增值。 這會留下您的應用程式可能無法接受的編號差距。 在發生此問題的情況下,TableAdapterManager 會提供一個 BackupDataSetBeforeUpdate 屬性,以在交易失敗時,以備份複本取代現有的資料集。

注意

只有在執行 TableAdapterManager.UpdateAll 方法時,備份複本才會在記憶體中。 因此,無法以程式設計方式存取此備份資料集,因為它會取代原始資料集,或在 TableAdapterManager.UpdateAll 方法完成執行時立即超出範圍。

修改產生的儲存程式碼以執行階層式更新

呼叫 TableAdapterManager.UpdateAll 方法並傳入包含關聯資料表的資料集名稱,可將資料集內關聯資料表的變更儲存至資料庫。 例如,執行 TableAdapterManager.UpdateAll(NorthwindDataset) 方法,以將 NorthwindDataset 中所有資料表的更新傳送至後端資料庫。

從 [資料來源] 視窗置放項目後,程式碼會自動新增至 Form_Load 事件,以填入每個資料表 (TableAdapter.Fill 方法)。 程式碼也會新增至 BindingNavigator 的 [儲存] 按鈕 Click 事件,以將資料集的資料存回資料庫 (TableAdapterManager.UpdateAll 方法)。

產生的儲存程式碼也包含一行會呼叫 CustomersBindingSource.EndEdit 方法的程式碼。 更精確的說,它會對加入表單的第一個 BindingSource 呼叫 EndEdit 方法。 換言之,只會針對從 [資料來源] 視窗拖曳至表單上的第一個資料表產生此程式碼。 EndEdit 呼叫會認可目前正在編輯的所有資料繫結控制項中,所有正在進行的變更。 因此,當資料繫結控制項還有焦點時,您可以按一下 [儲存] 按鈕,就會在實際儲存 (TableAdapterManager.UpdateAll 方法) 之前,先認可該控制項中所有暫止的編輯項目。

注意

資料集設計工具 只會為已卸除至表單的第一個資料表新增 BindingSource.EndEdit 程式碼。 因此,您必須對表單上每個關聯資料表,加入一行程式碼以呼叫 BindingSource.EndEdit 方法。 在此逐步說明中,這表示您必須加入 OrdersBindingSource.EndEdit 方法的呼叫。

  1. 按兩下 BindingNavigator 上的 [儲存] 按鈕,以在程式碼編輯器中開啟 Form1

  2. 在呼叫 OrdersBindingSource.EndEdit 方法的程式碼行後方,加入一行程式碼以呼叫 CustomersBindingSource.EndEdit 方法。 [儲存] 按鈕 Click 事件中的程式碼應與下列類似:

    this.Validate();
    this.customersBindingSource.EndEdit();
    this.ordersBindingSource.EndEdit();
    this.tableAdapterManager.UpdateAll(this.northwindDataSet);
    

除了將資料儲存至資料庫前,先認可關聯子資料表的變更外,您可能也必須先認可新建立的父記錄,才能將子記錄加入至資料集。 換言之,您可能必須先將新的父記錄 (Customer) 新增至資料集,外部索引鍵條件約束才會允許新的子記錄 (Orders) 新增至資料集。 若要完成此工作,您可以使用子 BindingSource.AddingNew 事件。

注意

您是否必須提交新的父記錄,要取決於繫結至資料來源所使用的控制項類型。 在本逐步解說中,您會使用個別控制項繫結至父資料表。 這需要額外的程式碼來提交新的父記錄。 若父記錄改爲顯示在複雜繫結控制項中,例如 DataGridView,就不需要為父記錄進行額外的 EndEdit 呼叫。 因為控制項的基礎資料繫結功能會處理新記錄的認可。

加入程式碼以在新增子記錄前先認可資料集中的父記錄

  1. 建立 OrdersBindingSource.AddingNew 事件的事件處理常式。

    • 在設計檢視中開啟 Form1,選取元件匣中的 [OrdersBindingSource],再選取 [屬性] 視窗中的 [事件],然後按兩下 [AddingNew] 事件。
  2. 在事件處理常式中新增一行呼叫 CustomersBindingSource.EndEdit 方法的程式碼。 OrdersBindingSource_AddingNew 事件處理常式中的程式碼應該與下列類似:

    this.customersBindingSource.EndEdit();
    

TableAdapterManager 參考

根據預設,當您建立包含相關資料表的資料集時,會產生 TableAdapterManager 類別。 若要防止產生類別,請將資料集的 Hierarchical Update 屬性值變更為 False。 當您將具有關聯的資料表拖曳到 Windows Form 或 WPF 頁面的設計介面時,Visual Studio 會宣告類別的成員變數。 如果您沒有使用資料繫結,則必須手動宣告變數。

TableAdapterManager 類別不是 .NET 型別。 因此,您無法在文件中查閱。 它會在設計階段建立,作為資料集建立流程的一部分。

以下是 TableAdapterManager 類別的常用方法和屬性:

member 描述
UpdateAll 方法 儲存所有資料表中的所有資料。
BackUpDataSetBeforeUpdate 屬性 決定在執行 TableAdapterManager.UpdateAll 方法之前是否要先建立資料集的備份複本 (布林)。
tableNameTableAdapter 屬性 代表 TableAdapter。 產生的 TableAdapterManager 包含其所管理之每個 TableAdapter 的屬性。 例如,具有 Customers 和 Orders 資料表的資料集會產生包含 CustomersTableAdapterOrdersTableAdapter 屬性的 TableAdapterManager
UpdateOrder 屬性 控制個別插入、更新和刪除命令的順序。 將其設定為 TableAdapterManager.UpdateOrderOption 列舉中的其中一個值。

根據預設,UpdateOrder 會設定為 InsertUpdateDelete。 這表示會對資料集中的所有資料表依序執行插入、更新和刪除。