共用方式為


使用 CommandBuilders 產生命令

SelectCommand 屬性在執行時動態指定,例如透過查詢工具接收使用者的文字指令時,你可能無法在設計時指定適當的 InsertCommandUpdateCommandDeleteCommand 。 如果DataTable對應或是從單一的資料庫表格產生,您可以利用DbCommandBuilder物件來自動產生DeleteCommandInsertCommandUpdateCommandDbDataAdapter

您至少必須設定 SelectCommand 屬性,才能讓自動產生命令運作。 屬性所 SelectCommand 擷取的數據表架構會決定自動產生的 INSERT、UPDATE 和 DELETE 語句的語法。

DbCommandBuilder必須執行 SelectCommand ,才能傳回建構 INSERT、UPDATE 和 DELETE SQL 命令所需的元數據。 因此,可能需要進一步查詢數據源,這可能會影響效能。 若要達到最佳效能,請明確指定命令,而不是使用 DbCommandBuilder

SelectCommand 還必須傳回至少一個主索引鍵或唯一的資料行。 如果沒有存在,將會產生 InvalidOperation 例外狀況,並且不會執行命令。

當與DataAdapter相關聯時,如果DbCommandBuilderInsertCommandUpdateCommandDeleteCommand屬性是空引用,則DataAdapter會自動生成這些屬性。 Command如果屬性已經存在 ,則會使用現有的 Command

聯結兩個或多個數據表所建立的資料庫檢視不會被視為單一資料庫數據表。 在此實例中,您無法使用 DbCommandBuilder 來自動產生命令;您必須明確指定命令。 如需明確指定命令以將更新解析回 DataSet 資料來源的相關信息,請參閱 使用 DataAdapters 更新資料來源

您可能要將輸出參數對應回更新過的 DataSet 列。 其中一個常見工作是從數據源擷取自動產生的識別欄位或時間戳的值。 預設 DbCommandBuilder 不會將輸出參數對應至更新數據列中的數據行。 在此實例中,您必須明確指定命令。 如需將自動產生的識別欄位對應回插入資料列之數據行的範例,請參閱 擷取識別或自動編號值

自動產生的命令規則

下表顯示如何產生自動產生命令的規則。

指令 規則
InsertCommand 在數據來源中對表格中所有具有RowStateAdded的資料列插入一行。 插入可更新之所有數據行的值(但不是標識列、表達式或時間戳等數據行)。
UpdateCommand 更新資料來源的列,以符合資料表中所有具有RowStateModified的列。 更新所有數據行的值,但無法更新的數據行除外,例如身分識別或表達式。 更新所有在數據來源中符合行主鍵列值的數據列,且數據來源中其餘數據列符合行原始值的數據行。 如需詳細資訊,請參閱本主題中稍後的「更新和刪除的樂觀併發模型」。
DeleteCommand 刪除數據源中資料表具有RowStateDeleted的所有資料列。 刪除所有資料列,其中資料行中欄位值符合該資料列的主鍵欄位值,並且資料來源的其他欄位符合該資料列的原始值。 如需詳細資訊,請參閱本主題中稍後的「更新和刪除的樂觀併發模型」。

更新和刪除的樂觀並發控制模型

針對 UPDATE 和 DELETE 語句自動產生命令的邏輯是以 開放式並行存取為基礎,也就是說,記錄不會鎖定進行編輯,而且可以隨時由其他使用者或進程修改。 由於記錄可能在從 SELECT 語句傳回之後修改,但在發出 UPDATE 或 DELETE 語句之前,自動產生的 UPDATE 或 DELETE 語句會包含 WHERE 子句,指定只有在數據列包含所有原始值且尚未從數據源中刪除時,才會更新數據列。 這樣做是為了避免覆寫新的數據。 當自動產生的更新嘗試更新已刪除的資料列或資料列中不含有在 DataSet 中找到的原始值時,該命令將不會影響任何記錄,並會擲回 DBConcurrencyException

如果您希望 UPDATE 或 DELETE 能夠完成,不論原始值為何,您必須明確設定 UpdateCommandDataAdapter,而不是依賴自動產生命令。

自動命令產生邏輯的限制

下列限制適用於自動產生命令。

僅限不相關的數據表

自動命令產生邏輯會產生獨立數據表的 INSERT、UPDATE 或 DELETE 語句,而不考慮數據源上其他數據表的任何關聯性。 因此,如果呼叫 Update 提交資料庫中參與外鍵約束條件之欄的變更,可能會遭遇故障。 若要避免這個例外狀況,請勿使用 DbCommandBuilder 來更新外鍵條件約束中涉及的數據行;請改為明確指定用來執行作業的語句。

數據表和數據行名稱

如果數據行名稱或數據表名稱包含任何特殊字元,例如空格、句號、引號或其他非虛構字元,即使以括號分隔,自動命令產生邏輯可能會失敗。 根據提供者的不同,設定 QuotePrefix 和 QuoteSuffix 參數可能會允許生成邏輯處理空格,但無法跳脫特殊字元。 支援格式為 catalog.schema.table 的完全合格數據表名稱。

使用 CommandBuilder 自動產生 SQL 語句

若要自動產生 DataAdapter的 SQL 語句,請先設定 SelectCommandDataAdapter屬性,然後建立 CommandBuilder 物件,並將 指定為 自變數 DataAdapter ,讓 CommandBuilder 自動產生 SQL 語句。

' Assumes that connection is a valid SqlConnection object
' inside of a Using block.
Dim adapter As SqlDataAdapter = New SqlDataAdapter( _
  "SELECT * FROM dbo.Customers", connection)
Dim builder As SqlCommandBuilder = New SqlCommandBuilder(adapter)
builder.QuotePrefix = "["
builder.QuoteSuffix = "]"
// Assumes that connection is a valid SqlConnection object
// inside of a using block.
SqlDataAdapter adapter = new SqlDataAdapter(
  "SELECT * FROM dbo.Customers", connection);
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
builder.QuotePrefix = "[";
builder.QuoteSuffix = "]";

修改 SelectCommand

如果您在 INSERT、UPDATE 或 DELETE 命令自動產生之後修改 CommandTextSelectCommand ,則可能會發生例外狀況。 如果修改後的 SelectCommand.CommandText 中包含的架構資訊與在自動生成插入、更新或刪除命令時所使用的 SelectCommand.CommandText 不一致,則在未來對 DataAdapter.Update 方法的呼叫可能會嘗試存取當前由 SelectCommand 參照的表中的欄位,而會擲出例外狀況。

您可以呼叫 CommandBuilderRefreshSchema 方法,重新整理 CommandBuilder 所使用的架構資訊,以自動產生命令。

如果您想知道自動產生的命令,您可以使用GetInsertCommand物件的GetUpdateCommandGetDeleteCommandCommandBuilder方法來取得自動產生的命令參考,並檢查相關命令的CommandText屬性。

下列程式代碼範例會將自動產生的更新命令寫入主控台。

Console.WriteLine(builder.GetUpdateCommand().CommandText)
Console.WriteLine(builder.GetUpdateCommand().CommandText);

下列範例會在 Customers 數據集中重新建立 custDS 數據表。 RefreshSchema此方法會被呼叫以刷新自動產生的指令,並包含這些新的欄位資訊。

' Assumes an open SqlConnection and SqlDataAdapter inside of a Using block.
adapter.SelectCommand.CommandText = _
  "SELECT CustomerID, ContactName FROM dbo.Customers"
builder.RefreshSchema()

custDS.Tables.Remove(custDS.Tables("Customers"))
adapter.Fill(custDS, "Customers")
// Assumes an open SqlConnection and SqlDataAdapter inside of a using block.
adapter.SelectCommand.CommandText =
  "SELECT CustomerID, ContactName FROM dbo.Customers";
builder.RefreshSchema();

custDS.Tables.Remove(custDS.Tables["Customers"]);
adapter.Fill(custDS, "Customers");

另請參閱