次の方法で共有


自動生成コマンド

SelectCommand が実行時に動的に指定される場合、たとえばクエリ ツールを使用してユーザーの記述したクエリ構文を解釈する場合は、デザイン時に適切な InsertCommandUpdateCommand、または DeleteCommand を指定することはできません。DataTable を単一データベース テーブルに割り当てたり、単一データベースから生成する場合は、CommandBuilder オブジェクトを利用して自動的に DataAdapterDeleteCommandInsertCommand、および UpdateCommand を生成できます。

自動的なコマンド生成のための最低限の条件として、SelectCommand プロパティを設定する必要があります。SelectCommand で取得したテーブル スキーマによって、自動的に生成される INSERT、UPDATE、DELETE の各ステートメントの構文が決まります。

CommandBuilder は、INSERT、UPDATE、DELETE の各コマンドを生成するために SelectCommand を実行する必要があります。その結果、データ ソースへの追加のトリップが必要になるため、パフォーマンスの低下する可能性があります。最適のパフォーマンスを得るには、明示的にコマンドを指定し、CommandBuilder を使用しないようにします。

SelectCommand は少なくとも 1 つの主キーまたは一意の列を返す必要があります。どちらも存在しない場合は、InvalidOperation 例外が生成され、コマンドは生成されません。

DataAdapter との関連付けが行われていて、DataAdapterInsertCommandUpdateCommandDeleteCommand の各プロパティが null 参照である場合、CommandBuilder は自動的にこれらのプロパティを生成します。プロパティに対して既に Command が存在する場合は、既存の Command が使用されます。

複数のテーブルを結合して作成したデータベース ビューは、単一データベース テーブルとは見なされません。たとえば、コマンドは CommandBuilder を使用すると自動的に生成できないため、明示的に指定する必要がでてきます。DataSet に対する更新を元のデータ ソースに反映させるコマンドを明示的に設定する方法については、「DataAdapter および DataSet によるデータベースの更新」を参照してください。

出力パラメータを DataSet の更新行に割り当てることが必要な場合があります。一般的なタスクの 1 つは、データ ソースの自動的に生成された ID フィールドまたはタイムスタンプの値を取得することです。CommandBuilder は、既定では更新行の列に出力パラメータを割り当てません。その場合は、コマンドを明示的に指定する必要があります。自動的に生成された ID フィールドを挿入行の列に割り当てる例については、「ID 値および Autonumber 値の取得」を参照してください。

コマンド自動生成規則

コマンド自動生成の規則を次の表に示します。

コマンド 規則
InsertCommand RowState の設定が DataRowState.Added であるテーブル内のすべての行に対して、データ ソースの行を挿入する。更新可能なすべての列に対して値を挿入します。ただし、ID、式、タイムスタンプなどの列は除きます。
UpdateCommand RowState の設定 DataRowState.Modified に設定されているテーブル内のすべての行に対して、データ ソース側での行を更新する。ID や式などの更新不可能な列を除く、すべての列の値を更新します。データ ソースの列の値と該当行の主キー列の値が一致し、さらにデータ ソースのその他の列がその行の元の値と一致する、すべての行を更新します。詳細については、「更新および削除のオプティミスティック同時実行制御」の該当するセクションを参照してください。
DeleteCommand RowStateDataRowState.Deleted に設定されているテーブル内のすべての行についてデータ ソース側で行を削除する。列の値とその行の主キー列の値が一致し、さらにデータ ソースのその他の列が、その行の元の値と一致する、すべての行を削除します。詳細については、「更新および削除のオプティミスティック同時実行制御」の該当するセクションを参照してください。

更新および削除のオプティミスティック同時実行制御

UPDATE ステートメントおよび DELETE ステートメントに対する自動コマンド生成ロジックは、オプティミスティック同時実行制御に基づいています。これはつまり、編集時にレコードがロックされず、他のユーザーまたはプロセスがそのレコードをいつでも変更できることを意味します。レコードは SELECT コマンドによって返された後、UPDATE ステートメントまたは DELETE ステートメントの実行前に変更されている可能性もあるため、自動的に生成される UPDATE ステートメントまたは DELETE ステートメントには、元のすべての値を含み、データ ソースから削除されていない行だけを更新するように指定した WHERE 句が含まれます。これにより、新しいデータが上書きされるのを防ぎます。自動的に生成された更新コマンドが削除済みまたは DataSet にある元の値が含まれていない行を更新しようとすると、コマンドはどのレコードにも反映されずに、DBConcurrencyException がスローされます。

元の値とは関係なく UPDATE または DELETE を実行する場合は、DataAdapter に明示的に UpdateCommand を設定し、自動コマンド生成は行わないでください。

自動コマンド生成ロジックの制限事項

自動コマンド生成には次の制限事項が適用されます。

リレーションシップのないテーブルに限定

自動コマンド生成ロジックでは、データ ソースの他のテーブルへのリレーションシップを考慮せずに、独立したテーブルを対象として INSERT、UPDATE、または DELETE の各ステートメントを生成します。その結果、Update を呼び出してデータベースの外部キー制約に関係する列に対する変更を発行すると、エラーが発生する場合があります。このような例外を防ぐには、外部キー制約に関係する列の更新には CommandBuilder を使用せず、更新操作を実行するステートメントを明示的に指定します。

テーブル名と列名

列名またはテーブル名にスペース、ピリオド (.)、疑問符 (?)、引用符、その他の英数字以外の特殊文字が含まれていると、たとえそれらの文字が角かっこで囲まれていても、自動コマンド生成ロジックはエラーになります。catalog.schema.table の形式をとる完全修飾テーブル名はサポートされています。

CommandBuilder による SQL ステートメントの自動生成

DataAdapter に対して SQL ステートメントを自動的に生成するには、まず DataAdapterSelectCommand プロパティを設定します。次に、CommandBuilder オブジェクトを作成し、CommandBuilder で SQL ステートメントを自動的に生成する DataAdapter を引数として指定します。

Dim custDA As SqlDataAdapter = New SqlDataAdapter("SELECT * FROM Customers", nwindConn)
Dim custCB As SqlCommandBuilder = New SqlCommandBuilder(custDA)
custCB.QuotePrefix = "["
custCB.QuoteSuffix = "]"

Dim custDS As DataSet = New DataSet

nwindConn.Open()
custDA.Fill(custDS, "Customers")

' Code to modify data in the DataSet here.

' Without the SqlCommandBuilder, this line would fail.
custDA.Update(custDS, "Customers")
nwindConn.Close()
[C#]
SqlDataAdapter custDA = new SqlDataAdapter("SELECT * FROM Customers", nwindConn);
SqlCommandBuilder custCB = new SqlCommandBuilder(custDA);
custCB.QuotePrefix = "[";
custCB.QuoteSuffix = "]";

DataSet custDS = new DataSet();

nwindConn.Open();
custDA.Fill(custDS, "Customers");

// Code to modify data in the DataSet here.

// Without the SqlCommandBuilder, this line would fail.
custDA.Update(custDS, "Customers");
nwindConn.Close();

SelectCommand の変更

INSERT、UPDATE、または DELETE の各コマンドを自動生成した後に SelectCommandCommandText を変更すると、例外が発生します。変更された SelectCommand.CommandText に、INSERT、UPDATE、または DELETE の各コマンドの自動生成時に使用した SelectCommand.CommandText と矛盾するスキーマ情報が含まれている場合、後続の DataAdapter.Update メソッド呼び出しでアクセスする列は SelectCommand によって参照された現在のテーブルには存在しない可能性があり、例外が発生します。

CommandBuilderRefreshSchema メソッドを呼び出すことで、自動的にコマンドを生成する CommandBuilder が使用するスキーマ情報を更新できます。

どのコマンドが自動的に生成されたかを確認するには、CommandBuilder オブジェクトの GetInsertCommandGetUpdateCommandGetDeleteCommand の各メソッドを使用して、自動的に生成されたコマンドへの参照を取得し、関連付けられている CommandCommandText プロパティをチェックします。

自動的に生成された更新コマンドをコンソールに出力するサンプル コードを次に示します。

Console.WriteLine(custCB.GetUpdateCommand().CommandText)

次に示すのは、前述の例 (「CommandBuilder による SQL ステートメントの自動生成」にあるセクションの例) の続きのコードです。この例では、CompanyName 列を ContactName 列に置き換えて Customers テーブルを再作成します。RefreshSchema メソッドを呼び出し、新しい列情報を使用して、自動的に生成されたコマンドを更新します。

nwindConn.Open()

custDA.SelectCommand.CommandText = "SELECT CustomerID, ContactName FROM Customers"
custCB.RefreshSchema()

custDS.Tables.Remove(custDS.Tables("Customers"))
custDA.Fill(custDS, "Customers")

' Code to modify the new table in the DataSet here.

' Without the call to RefreshSchema, this line would fail.
custDA.Update(custDS, "Customers")

nwindConn.Close()
[C#]
nwindConn.Open();

custDA.SelectCommand.CommandText = "SELECT CustomerID, ContactName FROM Customers";
custCB.RefreshSchema();

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

// Code to modify the new table in the DataSet here.

// Without the call to RefreshSchema, this line would fail.
custDA.Update(custDS, "Customers");

nwindConn.Close();

参照

.NET Framework データ プロバイダによるデータのアクセス | OleDbDataAdapter クラス | OdbcDataAdapter クラス | SqlDataAdapter クラス