適用対象: .NET Framework .NET
.NET Standard
SelectCommand オブジェクトの DbDataAdapter プロパティが実行時に動的に指定される場合 (たとえば、ユーザーからテキスト形式のコマンドを取得するクエリ ツールを使用する場合など)、デザイン時に適切な InsertCommand、UpdateCommand、または DeleteCommand を指定できない場合があります。
DataTable を単一データベース テーブルに割り当てたり、単一データベースから生成する場合は、DbCommandBuilder オブジェクトを利用して自動的に DeleteCommand の InsertCommand、UpdateCommand、および DbDataAdapter を生成できます。
注
Microsoft SqlClient Data Provider for SQL Server では、SqlDataAdapter クラスは DbDataAdapter クラスから派生し、 SqlCommandBuilder クラスは DbCommandBuilder クラスから派生します。
コマンドを自動的に生成するための最低限の条件として、SelectCommand プロパティを設定する必要があります。
SelectCommand プロパティによって取得されるテーブル スキーマによって、自動的に生成されるINSERT、UPDATE、およびDELETEステートメントの構文が決まります。
DbCommandBuilderは、SelectCommand、INSERT、および SQL コマンドの構築に必要なメタデータを返すために、UPDATEDELETE実行する必要があります。 その結果、データ ソースへの追加のトリップが必要になるため、パフォーマンスが低下する可能性があります。 最適のパフォーマンスを実現するには、明示的にコマンドを指定し、DbCommandBuilder を使用しないようにします。
注
SelectCommand は少なくとも 1 つの主キーまたは一意の列を返す必要があります。 1 つも存在しない場合は、InvalidOperation 例外が生成され、コマンドは生成されません。
DataAdapter との関連付けが行われていて、DbCommandBuilder の InsertCommand、UpdateCommand、DeleteCommand の各プロパティが null 参照である場合、DataAdapter は自動的にこれらのプロパティを生成します。 プロパティに対して既に Command が存在する場合は、既存の Command が使用されます。
複数のテーブルを結合して作成したデータベース ビューは、単一データベース テーブルとは見なされません。 このインスタンスでは、コマンドを自動的に生成するために DbCommandBuilder を使用することはできません。コマンドは明示的に指定する必要があります。
DataSet に対する更新を元のデータ ソースに反映させるコマンドを明示的に設定する方法については、「DataAdapter を使用してデータ ソースを更新する」を参照してください。
出力パラメーターを DataSet の更新行に割り当てることが必要な場合があります。 一般的なタスクの 1 つは、データ ソースの自動的に生成された ID フィールドまたはタイムスタンプの値を取得することです。
DbCommandBuilder は、既定では更新行の列に出力パラメーターを割り当てません。 このインスタンスでは、コマンドを明示的に指定する必要があります。 自動的に生成された ID フィールドを挿入行の列に割り当てる例については、「ID 値または autonumber 値の取得」を参照してください。
自動生成されたコマンドの規則
コマンドの自動生成規則を次の表に示します。
| コマンド | ルール |
|---|---|
InsertCommand |
RowState が Added に設定されているテーブル内のすべての行に対して、データ ソースの行を挿入します。 更新可能なすべての列に対して値を挿入します (ただし、ID、式、タイムスタンプなどの列は除きます)。 |
UpdateCommand |
RowState が Modified に設定されているテーブル内のすべての行に対して、データ ソースの行を更新します。 ID や式などの更新不可能な列を除く、すべての列の値を更新します。 データ ソースの列の値と該当行の主キー列の値が一致し、さらにデータ ソースのその他の列がその行の元の値と一致する、すべての行を更新します。 詳細については、このトピックで後述する「更新および削除のオプティミスティック コンカレンシー モデル」を参照してください。 |
DeleteCommand |
RowState が Deleted に設定されているテーブル内のすべての行に対して、データ ソースの行を削除します。 列の値とその行の主キー列の値が一致し、さらにデータ ソースのその他の列がその行の元の値と一致する、すべての行を削除します。 詳細については、このトピックで後述する「更新と削除のオプティミスティック同時実行制御モデル」を参照してください。 |
更新と削除のオプティミスティック同時実行制御モデル
UPDATEステートメントとDELETE ステートメントに対してコマンドを自動的に生成するロジックは、オプティミスティック コンカレンシーに基づいています。つまり、レコードは編集用にロックされず、他のユーザーやプロセスによっていつでも変更できます。 レコードは SELECT ステートメントから返された後、 UPDATE または DELETE ステートメントが発行される前に変更された可能性があるため、自動的に生成された UPDATE または DELETE ステートメントには WHERE 句が含まれ、行に元の値がすべて含まれ、データ ソースから削除されていない場合にのみ行が更新されることを指定します。 これにより、新しいデータが上書きされるのを防ぎます。
注
自動的に生成された更新コマンドが削除済みの行、または DataSet にある元の値が含まれていない行を更新しようとすると、コマンドはどのレコードにも反映されずに、DBConcurrencyException がスローされます。
元の値に関係なくUPDATEまたはDELETEを完了する場合は、UpdateCommandのDataAdapterを明示的に設定し、コマンドの自動生成に依存しないようにする必要があります。
コマンドの自動生成ロジックに関する制限事項
コマンドの自動生成には次の制限事項が適用されます。
関連のないテーブルのみ
自動コマンド生成ロジックでは、データ ソースの他のテーブルとのリレーションシップを考慮せずに、スタンドアロン テーブルの INSERT、 UPDATE、または DELETE ステートメントが生成されます。 その結果、Update を呼び出してデータベースの外部キー制約に関係する列に対する変更を発行すると、エラーが発生する場合があります。 このような例外を防ぐには、外部キー制約に関係する列の更新には DbCommandBuilder を使用せず、更新操作を実行するステートメントを明示的に指定します。
テーブル名と列名
列名またはテーブル名にスペース、ピリオド (.)、疑問符 (?)、引用符、その他の英数字以外の特殊文字が含まれていると、それらの文字が角かっこで囲まれていても、コマンドの自動生成ロジックはエラーになる場合があります。 プロバイダーによって異なりますが、QuotePrefix パラメーターと QuoteSuffix パラメーターを設定すると、生成ロジックではスペースを処理できる場合があっても、特殊文字をエスケープできません。 catalog.schema.table の形式をとる、テーブルの完全修飾名はサポートされています。
CommandBuilder を使用して SQL ステートメントを自動的に生成する
DataAdapter に対して SQL ステートメントを自動的に生成するには、まず SelectCommand の DataAdapter プロパティを設定します。次に、CommandBuilder オブジェクトを作成し、DataAdapter で SQL ステートメントを自動的に生成する CommandBuilder を引数として指定します。
// Assumes that connection is a valid SqlConnection object
// inside of a using block.
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = new SqlCommand(queryString, connection);
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
builder.QuotePrefix = "[";
builder.QuoteSuffix = "]";
SelectCommand を変更する
CommandText、SelectCommand、またはINSERTコマンドが自動的に生成された後にUPDATEのDELETEを変更すると、例外が発生する可能性があります。 変更された SelectCommand.CommandText に、INSERT、UPDATE、または DELETE の各コマンドの自動生成時に使用した SelectCommand.CommandText と矛盾するスキーマ情報が含まれている場合、後続の DataAdapter.Update メソッド呼び出しでアクセスする列は SelectCommand によって参照された現在のテーブルには存在しない可能性があり、例外が発生します。
CommandBuilder の RefreshSchema メソッドを呼び出すことで、自動的にコマンドを生成する CommandBuilder が使用するスキーマ情報を更新できます。
どのコマンドが自動的に生成されたかを確認するには、GetInsertCommand オブジェクトの GetUpdateCommand、GetDeleteCommand、CommandBuilder の各メソッドを使用して、自動的に生成されたコマンドへの参照を取得し、関連付けられているコマンドの CommandText プロパティを確認します。
自動的に生成された更新コマンドをコンソールに出力するコード サンプルを次に示します。
// Generate the update command automatically by SqlCommandBuilder
Console.WriteLine(builder.GetUpdateCommand().CommandText);
次の例では、データセットにテーブルを再作成します。 RefreshSchema メソッドを呼び出し、新しい列情報を使用して、自動的に生成されたコマンドを更新します。
// Assumes an open SqlConnection and SqlDataAdapter inside of a using block.
adapter.SelectCommand.CommandText = newQueryString;
builder.RefreshSchema();
dataSet.Tables.Remove(dataSet.Tables[tableName]);
adapter.Fill(dataSet, tableName);