コマンド オブジェクトは、パラメーターを使用して SQL ステートメントまたはストアド プロシージャに値を渡すことによって、型チェックと検証の機能を実現します。 コマンド テキストとは異なり、パラメーターの入力は実行可能なコードとしてではなく、リテラル値として扱われます。 これにより、攻撃者がサーバーのセキュリティを侵害するコマンドを SQL ステートメントに "注入" する SQL インジェクション攻撃を防ぐことができます。
パラメーター化コマンドによりクエリ実行パフォーマンスも向上します。これは、データベース サーバーが入力コマンドを適切なキャッシュ済みクエリ プランに正確に一致させるのに役立つためです。 詳細については、「実行プランのキャッシュと再利用」および「パラメーターと実行プランの再利用」を参照してください。 セキュリティおよびパフォーマンス上の利点に加え、パラメーター化コマンドを使用すると、データ ソースに渡す値を簡単に扱うことができます。
DbParameter オブジェクトは、コンストラクターを使って作成できるほか、 DbParameterCollection コレクションの Add
メソッドを呼び出し、 DbParameterCollection にオブジェクトを追加することによって作成することもできます。
Add
メソッドは、コンストラクター引数または既存のパラメーター オブジェクトを入力として受け取ります。この点はデータ プロバイダーによっても異なります。
ParameterDirection プロパティの指定
パラメーターを追加する際は、入力パラメーターとは別に、パラメーターの ParameterDirection プロパティを指定する必要があります。
ParameterDirection
で使用できる ParameterDirection の値を次の表に示します。
メンバー名 | 説明 |
---|---|
Input | このパラメーターは入力パラメーターです。 既定値です。 |
InputOutput | このパラメーターは入力と出力の両方の機能を持っています。 |
Output | このパラメーターは出力パラメーターです。 |
ReturnValue | パラメーターは、ストアド プロシージャ、組み込み関数、ユーザー定義関数などの操作からの戻り値を表します。 |
パラメーターのプレースホルダーの使用
パラメーターのプレースホルダーの構文はデータ ソースに依存します。 .NET Framework のデータ プロバイダーによって、パラメーターおよびパラメーターのプレースホルダーの名前付けや指定方法が異なります。 次の表に示すように、データ ソースごとに固有の構文が採用されています。
データ プロバイダー | パラメーターの名前付け構文 |
---|---|
System.Data.SqlClient |
@
parametername形式の名前付きパラメーターが使用されます。 |
System.Data.OleDb | 疑問符 (? ) で指定される位置パラメーター マーカーが使用されます。 |
System.Data.Odbc | 疑問符 (? ) で指定される位置パラメーター マーカーが使用されます。 |
System.Data.OracleClient |
:
parmname (または parmname) 形式の名前付きパラメーターが使用されます。 |
パラメーターのデータ型の指定
パラメーターのデータ型は .NET Framework データ プロバイダーに固有です。 型が指定されている場合は、Parameter
の値がデータ ソースに渡される前に、その値が .NET Framework データ プロバイダー型に変換されます。
Parameter
オブジェクトの DbType
プロパティを特定の Parameter
に設定する一般的な方法で DbTypeの型を指定することもできます。
Parameter
オブジェクトの .NET Framework データ プロバイダー型は、Value
オブジェクトの Parameter
の .NET Framework 型、または DbType
オブジェクトの Parameter
から推論されます。
Parameter
値として渡されるオブジェクトまたは指定された Parameter
に基づいて推論される DbType
型を、次の表に示します。
.NET Framework 型 | DbType | SqlDbType | OleDbType | OdbcType | OracleType |
---|---|---|---|---|---|
Boolean | ブール型 | ビット | ブール型 | ビット | バイト |
Byte | バイト | TinyInt | UnsignedTinyInt | TinyInt | バイト |
byte[] | 2 項 | VarBinary。 バイト配列が VarBinary の最大サイズ (8000 バイト) より大きい場合、この暗黙の変換はエラーになります。8000 バイトを超えるバイト配列の場合は、明示的に SqlDbType を設定してください。 | VarBinary | 2 項 | 未加工 |
Char | char から SqlDbType への推論はサポートされていません。 | イワナ | イワナ | バイト | |
DateTime | 日付と時間 | 日付と時間 | DBタイムスタンプ | 日付と時間 | 日付と時間 |
DateTimeOffset | DateTimeOffset (日付と時刻のオフセット) | SQL Server 2008 の DateTimeOffset。 SQL Server 2008 より前のバージョンの SQL Server では、DateTimeOffset から SqlDbType への推論はサポートされていません。 | 日付と時間 | ||
Decimal | 10 進法 | 10 進法 | 10 進法 | 数字 | 数値 |
Double | ダブル | 浮く | ダブル | ダブル | ダブル |
Single | シングル | 本当の | シングル | 本当の | 浮く |
Guid | GUID | ユニーク識別子 | GUID | ユニーク識別子 | 未加工 |
Int16 | Int16 | スモールイント | スモールイント | スモールイント | Int16 |
Int32 | Int32 | int | int | int | Int32 |
Int64 | Int64 | ビッグイント (BigInt) | ビッグイント (BigInt) | ビッグイント (BigInt) | 数値 |
Object | オブジェクト | バリアント | バリアント | Object から OdbcType への推論はサポートされていません。 | ブロッブ |
String | 糸 | NVarChar。 文字列が NVarChar の最大サイズ (4000 文字) より大きい場合、この暗黙の変換はエラーになります。 4000 文字を超える文字列の場合は、明示的に SqlDbTypeを設定してください。 | VarWChar | NVarChar | NVarChar |
TimeSpan | 時刻 | SQL Server 2008 の Time。 SQL Server 2008 より前のバージョンの SQL Server では、TimeSpan から SqlDbType への推論はサポートされていません。 | DBTime | 時刻 | 日付と時間 |
UInt16 | UInt16 | UInt16 から SqlDbType への推論はサポートされていません。 | 符号なし短整数 | int | UInt16 |
UInt32 | UInt32 | UInt32 から SqlDbType への推論はサポートされていません。 | 符号なし整数 | ビッグイント (BigInt) | UInt32 |
UInt64 | UInt64 | UInt64 から SqlDbType への推論はサポートされていません。 | アンサインドビッグイント | 数字 | 数値 |
AnsiString | VarChar(バーチャー) | VarChar(バーチャー) | VarChar(バーチャー) | VarChar(バーチャー) | |
AnsiStringFixedLength | イワナ | イワナ | イワナ | イワナ | |
通貨 | 通貨 | 通貨 |
OdbcType から Currency への推論はサポートされていません。 |
数値 | |
日付 | SQL Server 2008 の Date。 SQL Server 2008 より前のバージョンの SQL Server では、Date から SqlDbType への推論はサポートされていません。 | DBDate | 日付 | 日付と時間 | |
SByte | SByte から SqlDbType への推論はサポートされていません。 | TinyInt | SByte から OdbcType への推論はサポートされていません。 |
SByte | |
StringFixedLength | NChar(エヌキャラ) | WChar | NChar(エヌキャラ) | NChar(エヌキャラ) | |
時刻 | SQL Server 2008 の Time。 SQL Server 2008 より前のバージョンの SQL Server では、Time から SqlDbType への推論はサポートされていません。 | DBTime | 時刻 | 日付と時間 | |
VarNumeric | VarNumeric から SqlDbType への推論はサポートされていません。 | VarNumeric | VarNumeric から OdbcType への推論はサポートされていません。 |
数値 | |
ユーザー定義型 ( SqlUserDefinedAggregateAttributeを持つオブジェクト) | プロバイダーに応じて Object または String (SqlClient は常に Object を返し、Odbc は常に String を返します。OleDb マネージド データ プロバイダーはいずれかを表示できます)。 | SqlUserDefinedTypeAttribute がある場合は SqlDbType.Udt、それ以外の場合は Variant。 | OleDbType.VarWChar (値が null の場合)、それ以外の場合は OleDbType.Variant。 | OdbcType.NVarChar | サポート外 |
注
decimal から他の型への変換は縮小変換になるため、decimal 値は最も近い整数値に切り捨てられます。 変換結果が対象の型にならなかった場合、 OverflowException がスローされます。
注
サーバーに NULL パラメーター値を送信する場合は、DBNull (Visual Basic の場合は null
) ではなく、Nothing
を指定する必要があります。 システムの null 値は、値のない空オブジェクトです。
DBNull は、null 値を表すために使用します。 データベースの NULL 値の詳細については、「 Handling Null Values」を参照してください。
パラメーター情報の派生
DbCommandBuilder
クラスを使用してストアド プロシージャからパラメーターを派生させることができます。
SqlCommandBuilder
クラスと OleDbCommandBuilder
クラスはどちらも静的メソッド DeriveParameters
を提供します。このメソッドは、ストアド プロシージャから得られたパラメーター情報を使用して、コマンド オブジェクトのパラメーター コレクションを設定します。
DeriveParameters
はコマンドの既存のパラメーター情報を上書きします。
注
パラメーター情報を派生させた場合、情報を取得するためにデータ ソースへのラウンド トリップが 1 つ増えるため、パフォーマンスが低下します。 パラメーター情報がデザイン時にわかっている場合は、パラメーターを明示的に設定することでアプリケーションのパフォーマンスを改善できます。
詳細については、「CommandBuilder でのコマンドの生成」を参照してください。
SqlCommand およびストアド プロシージャでのパラメーターの使用
ストアド プロシージャは、データドリブンのアプリケーションに多くの利点を提供します。 ストアド プロシージャを使用すると、データベースの操作を単一のコマンドにカプセル化し、最大のパフォーマンスが得られるように最適化し、さらに追加のセキュリティ機能を使用して、セキュリティを強化することができます。 ストアド プロシージャは、ストアド プロシージャ名の後にパラメーター引数を記述して SQL ステートメントとして渡すことで呼び出すことができますが、ADO.NET の Parameters オブジェクトの DbCommand コレクションを使用すると、ストアド プロシージャ パラメーターをより明示的に定義でき、出力パラメーターや戻り値にもアクセスできます。
注
パラメーター化されたステートメントは、クエリ プランの再利用を可能にする sp_executesql
を使用してサーバー上で実行されます。
sp_executesql
バッチ内のローカル カーソルまたはローカル変数は、 sp_executesql
を呼び出すバッチでは認識されません。 データベース コンテキストの変更は、 sp_executesql
ステートメント終了時まで有効です。 詳細については、「sp_executesql (Transact-SQL)」を参照してください。
SqlCommand でパラメーターを使用して SQL Server のストアド プロシージャを実行する場合は、 Parameters コレクションに追加したパラメーターの名前が、ストアド プロシージャ内のパラメーター マーカーの名前と一致している必要があります。 .NET Framework Data Provider for SQL Server は、SQL ステートメントまたはストアド プロシージャにパラメーターを渡す場合の疑問符 (?) プレースホルダーをサポートしていません。 ストアド プロシージャ内のパラメーターは名前付きのパラメーターと見なされ、一致するパラメーター マーカーが検索されます。 たとえば、 CustOrderHist
ストアド プロシージャが、 @CustomerID
という名前のパラメーターで定義されているとします。 このストアド プロシージャを実行する場合、実行元のコードでも @CustomerID
という名前のパラメーターを使用する必要があります。
CREATE PROCEDURE dbo.CustOrderHist @CustomerID varchar(5)
例
次の例では、 Northwind
サンプル データベースにある SQL Server ストアド プロシージャを呼び出す方法を説明します。 ストアド プロシージャの名前は dbo.SalesByCategory
で、 @CategoryName
データ型の nvarchar(15)
という名前の入力パラメーターを持ちます。 このコードでは、プロシージャの終了時に接続が破棄されるように、using ブロック内で新しい SqlConnection を作成しています。
SqlCommand オブジェクトおよび SqlParameter オブジェクトが作成され、それぞれのプロパティが設定されます。
SqlDataReader によって SqlCommand
が実行された後、ストアド プロシージャから結果セットが返されて、出力がコンソール ウィンドウに表示されます。
注
SqlCommand
オブジェクトと SqlParameter
オブジェクトを作成してから別個のステートメントでプロパティを設定する代わりに、オーバーロード コンストラクターを使用して複数のプロパティを 1 つのステートメントで設定することもできます。
static void GetSalesByCategory(string connectionString,
string categoryName)
{
using (SqlConnection connection = new(connectionString))
{
// Create the command and set its properties.
SqlCommand command = new()
{
Connection = connection,
CommandText = "SalesByCategory",
CommandType = CommandType.StoredProcedure
};
// Add the input parameter and set its properties.
SqlParameter parameter = new()
{
ParameterName = "@CategoryName",
SqlDbType = SqlDbType.NVarChar,
Direction = ParameterDirection.Input,
Value = categoryName
};
// Add the parameter to the Parameters collection.
command.Parameters.Add(parameter);
// Open the connection and execute the reader.
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine($"{reader[0]}: {reader[1]:C}");
}
}
else
{
Console.WriteLine("No rows found.");
}
reader.Close();
}
}
}
Shared Sub GetSalesByCategory(ByVal connectionString As String, _
ByVal categoryName As String)
Using connection As New SqlConnection(connectionString)
' Create the command and set its properties.
Dim command As SqlCommand = New SqlCommand()
command.Connection = connection
command.CommandText = "SalesByCategory"
command.CommandType = CommandType.StoredProcedure
' Add the input parameter and set its properties.
Dim parameter As New SqlParameter()
parameter.ParameterName = "@CategoryName"
parameter.SqlDbType = SqlDbType.NVarChar
parameter.Direction = ParameterDirection.Input
parameter.Value = categoryName
' Add the parameter to the Parameters collection.
command.Parameters.Add(parameter)
' Open the connection and execute the reader.
connection.Open()
Using reader As SqlDataReader = command.ExecuteReader()
If reader.HasRows Then
Do While reader.Read()
Console.WriteLine("{0}: {1:C}", _
reader(0), reader(1))
Loop
Else
Console.WriteLine("No rows returned.")
End If
End Using
End Using
End Sub
OleDbCommand または OdbcCommand によるパラメーターの使用
OleDbCommand または OdbcCommandでパラメーターを使用するときは、 Parameters
コレクションにパラメーターが追加されている順序が、ストアド プロシージャ内でパラメーターが定義されている順序と一致している必要があります。 .NET Framework Data Provider for OLE DB と .NET Framework Data Provider for ODBC は、ストアド プロシージャ内のパラメーターをプレースホルダーとして処理し、順にパラメーター値を適用します。 また、戻り値パラメーターは、 Parameters
コレクションに最初に追加されたパラメーターにする必要があります。
.NET Framework Data Provider for OLE DB と .NET Framework Data Provider for ODBC は、SQL ステートメントまたはストアド プロシージャにパラメーターを渡す場合の名前付きのパラメーターをサポートしていません。 この場合は、次の例に示すように、疑問符 (?) プレースホルダーを使用する必要があります。
SELECT * FROM Customers WHERE CustomerID = ?
したがって、 Parameter
コレクションに Parameters
オブジェクトを追加する順序は、パラメーターの疑問符 (?) プレースホルダーの位置と完全に対応している必要があります。
OleDb の例
Dim command As OleDbCommand = New OleDbCommand( _
"SampleProc", connection)
command.CommandType = CommandType.StoredProcedure
Dim parameter As OleDbParameter = command.Parameters.Add( _
"RETURN_VALUE", OleDbType.Integer)
parameter.Direction = ParameterDirection.ReturnValue
parameter = command.Parameters.Add( _
"@InputParm", OleDbType.VarChar, 12)
parameter.Value = "Sample Value"
parameter = command.Parameters.Add( _
"@OutputParm", OleDbType.VarChar, 28)
parameter.Direction = ParameterDirection.Output
OleDbCommand command = new OleDbCommand("SampleProc", connection);
command.CommandType = CommandType.StoredProcedure;
OleDbParameter parameter = command.Parameters.Add(
"RETURN_VALUE", OleDbType.Integer);
parameter.Direction = ParameterDirection.ReturnValue;
parameter = command.Parameters.Add(
"@InputParm", OleDbType.VarChar, 12);
parameter.Value = "Sample Value";
parameter = command.Parameters.Add(
"@OutputParm", OleDbType.VarChar, 28);
parameter.Direction = ParameterDirection.Output;
Odbc の例
Dim command As OdbcCommand = New OdbcCommand( _
"{ ? = CALL SampleProc(?, ?) }", connection)
command.CommandType = CommandType.StoredProcedure
Dim parameter As OdbcParameter = command.Parameters.Add("RETURN_VALUE", OdbcType.Int)
parameter.Direction = ParameterDirection.ReturnValue
parameter = command.Parameters.Add( _
"@InputParm", OdbcType.VarChar, 12)
parameter.Value = "Sample Value"
parameter = command.Parameters.Add( _
"@OutputParm", OdbcType.VarChar, 28)
parameter.Direction = ParameterDirection.Output
OdbcCommand command = new OdbcCommand( _
"{ ? = CALL SampleProc(?, ?) }", connection);
command.CommandType = CommandType.StoredProcedure;
OdbcParameter parameter = command.Parameters.Add( _
"RETURN_VALUE", OdbcType.Int);
parameter.Direction = ParameterDirection.ReturnValue;
parameter = command.Parameters.Add( _
"@InputParm", OdbcType.VarChar, 12);
parameter.Value = "Sample Value";
parameter = command.Parameters.Add( _
"@OutputParm", OdbcType.VarChar, 28);
parameter.Direction = ParameterDirection.Output;