パラメータはコマンドの Transact-SQL(T-SQL)テキストとは別に値を送ります。 SQL文に値を連結または補間する代わりに、 SqlParameter オブジェクトを使いましょう。 パラメータはSQLインジェクションから守り、値のデータベース型を保持するのに役立ちます。
この記事の例では、connection という名前のオープン SqlConnection が AdventureWorks サンプル データベース をターゲットとしていることを前提としています。
C#の例は using Microsoft.Data.SqlClient;を必要とします。
SqlDbTypeを使う例もまた、using System.Data;が必要です。
入力パラメータの追加
コマンドテキスト内の各値プレースホルダーごとにパラメータを追加してください。 パラメータのSQL Server型を指定し、その値を割り当てます:
const string sql = """
SELECT ProductID, Name, ListPrice
FROM Production.Product
WHERE ProductSubcategoryID = @subcategoryId
AND ListPrice >= @minimumPrice
ORDER BY ListPrice;
""";
using var command = new SqlCommand(sql, connection);
command.Parameters.Add("@subcategoryId", SqlDbType.Int).Value = 2;
command.Parameters.Add("@minimumPrice", SqlDbType.Money).Value = 1_000m;
using SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(
$"{reader.GetInt32(0)}: {reader.GetString(1)} ({reader.GetDecimal(2):C})");
}
コマンド テキストと SqlParameter の両方で、パラメーター名の表記を同じにします。 SQL Serverはサーバー コレーションを使って変数名を照合するため、大文字と小文字を区別するコレーションを持つサーバーでは、一致しないと「スカラー変数を宣言しなければならない」エラーになります。
パラメーターのプレースホルダーを操作する
Microsoft.Data.SqlClientは@parameterNameという形式の名前付きパラメーターを使用します。 位置指定の疑問符(?)プレースホルダーはサポートされていません。
パラメータプレースホルダーは値を表し、SQL識別子や構文ではありません。 テーブル名、列名、ソート方向、あるいはSQLフラグメント全体にパラメータを使うことはできません。 アプリケーションが動的に識別子を選択した場合は、許可リストに対して検証を行い、検証後にのみコマンドテキストに追加してください。 すべてのデータ値をパラメータとして渡し続けてください。
テキストコマンドについては、Microsoft.Data.SqlClient はパラメータ化された文を sp_executesql を介して SQL Server に送ります。 文のテキストとパラメータ定義が同じままであれば、SQL Serverは実行計画を再利用できます。
パラメーターのデータ型を指定する
アプリケーションがターゲットSQL Server型を認識したときに明示的にSqlDbTypeを設定します。 また、該当する場合は、たとえば Size、Precision、Scale のようなタイプ固有のメタデータも設定してください。
この例は、Person.Person 内の nvarchar(50) および datetime 列に一致します:
const string sql = """
SELECT BusinessEntityID, FirstName, LastName
FROM Person.Person
WHERE LastName = @lastName
AND ModifiedDate >= @modifiedSince
ORDER BY BusinessEntityID;
""";
using var command = new SqlCommand(sql, connection);
SqlParameter lastName = command.Parameters.Add(
"@lastName",
SqlDbType.NVarChar,
50);
lastName.Value = "O'Brien";
SqlParameter modifiedSince = command.Parameters.Add(
"@modifiedSince",
SqlDbType.DateTime);
modifiedSince.Value = new DateTime(2013, 1, 1);
パラメータメタデータをターゲット列にマッチさせることで暗黙の変換を避け、文字列長や小数スケールの変更によってパラメータ定義が変わるのを防ぎます。
小数値は、精度とスケールを明示的に設定してください。
Production.ProductのWeight列はdecimal(8, 2)を使用します:
const string sql = """
SELECT ProductID, Name, Weight
FROM Production.Product
WHERE Weight >= @minimumWeight
ORDER BY Weight;
""";
using var command = new SqlCommand(sql, connection);
SqlParameter minimumWeight = command.Parameters.Add(
"@minimumWeight",
SqlDbType.Decimal);
minimumWeight.Precision = 8;
minimumWeight.Scale = 2;
minimumWeight.Value = 10.25m;
データベースのNULL値を渡します
データベース NULL を送信するには、Value を割り当ててください。 C# null は、通常のスカラーパラメーターに対応する SQL Server の NULL を表しません:
const string sql = """
SELECT SalesOrderID, OrderDate, SalesPersonID
FROM Sales.SalesOrderHeader
WHERE (@salesPersonId IS NULL OR SalesPersonID = @salesPersonId)
ORDER BY SalesOrderID;
""";
using var command = new SqlCommand(sql, connection);
SqlParameter salesPersonId = command.Parameters.Add(
"@salesPersonId",
SqlDbType.Int);
int? selectedSalesPersonId = null;
salesPersonId.Value = selectedSalesPersonId.HasValue
? selectedSalesPersonId.Value
: DBNull.Value;
推論されたメタデータは必要に応じて使用します
AddWithValueメソッドは実行時の値からパラメータのメタデータを推論します。 推論は、推論されたメタデータが安定していてデータベースの種類と一致している場合に便利です。 文字列の長さ、小数点の精度、その他の値特性が変化すると、異なるパラメータ定義を生成することができます。
ターゲットスキーマが既知の本番コマンドには、明示的なAddを持つSqlDbTypeを優先します。 C# null を AddWithValueに渡さず、型を指定して DBNull.Value を割り当ててください。
コマンドパラメータを再利用
パラメーターを一度作成し、異なる値で同じコマンドを実行する際は、その Value のみを変更するようにします:
const string sql = """
SELECT TOP (1) Name, ListPrice
FROM Production.Product
WHERE ProductSubcategoryID = @subcategoryId
ORDER BY ListPrice DESC;
""";
using var command = new SqlCommand(sql, connection);
SqlParameter subcategoryId = command.Parameters.Add(
"@subcategoryId",
SqlDbType.Int);
foreach (int id in new[] { 1, 2, 3 })
{
subcategoryId.Value = id;
using SqlDataReader reader = command.ExecuteReader();
if (reader.Read())
{
Console.WriteLine($"{id}: {reader.GetString(0)}");
}
}
同じ名前のパラメータを各実行ごとに追加しないでください。 既存のパラメータを再利用するか、コレクションをクリアしてから再構築してください。
パラメータの方向を設定する
Directionプロパティはコマンドがパラメータをどのように使用するかを示します。 ParameterDirection値に設定します。
| 方向 | Use |
|---|---|
| Input | ステートメントまたはストアドプロシージャに値を送ります。 この値は既定値です。 |
| Output | ストアドプロシージャの出力パラメータから値を受け取ります。 |
| InputOutput | 初期値を送り、更新された値を受け取ります。 |
| ReturnValue | T-SQL RETURN 文から整数値を受け取ります。 |
出力、入出力、戻り値のパラメーターについては、コマンドの実行が完了してから Value を参照します。 コマンドが行を返した場合は、その値を読む前に SqlDataReader を閉じるか廃棄してください。
ストアドプロシージャの完全な例については、「ストアドプロシージャでデータを変更する」を参照してください。
ストアドプロシージャでパラメーターを使用する
StoredProcedureを設定し、プロシージャのパラメータ名を使用します。 この例は、AdventureWorksに含まれる dbo.uspGetEmployeeManagers 手続きを次のように呼び出しています:
using var command = new SqlCommand(
"dbo.uspGetEmployeeManagers",
connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(
"@BusinessEntityID",
SqlDbType.Int).Value = 6;
using SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(
$"{reader.GetString(2)} {reader.GetString(3)}");
}
パラメータ名はストアドプロシージャで宣言された名前と一致しなければなりません。
テーブル値パラメーターの構成
テーブル値パラメータは、ストアドプロシージャやパラメーター化されたステートメントに複数行を送ります。 構成方法は以下の通りです:
-
SqlDbType.Structuredを設定します。 - TypeNameをデータベースのユーザー定義テーブルタイプに設定します。
-
DataTable、DbDataReader、または
IEnumerable<SqlDataRecord>の行ソースを割り当てます。
列が定義されているが行がない DataTable は、空のテーブルを送信します。 空の IEnumerable<SqlDataRecord> は ArgumentException をスローします。その入力フォームに対して 0 行を送信するには、C# の null を割り当てます。 テーブル値パラメータに DBNull.Value を割り当てないでください。
型の作成、行マッピング、完全な例については、「テーブル値パラメータ」を参照してください。
ストリーミング値を設定
Value に Stream、TextReader、XmlReader を割り当てることで、段階的に大きな値を設定します。 メモリ容量に制限のある転送を行う場合は、(max)、xml、または json のパラメーター型を使用します。 Microsoft.Data.SqlClient は、(max) 以外の文字型およびバイナリ型、ならびにレガシーな大容量オブジェクト型について、実行前にソースをバッファリングします。
パラメーターの型は値と一致しなければなりません:
| Value | 互換性のある SqlDbType 値 |
|---|---|
| Stream |
Binary、 VarBinary、またはレガシー Image タイプ |
| TextReader |
Char、 NChar、 NVarChar、 VarChar、レガシー Text および NText タイプ、 Xml、または Json |
| XmlReader |
Char、 NChar、 NVarChar、 VarChar、レガシー Text および NText タイプ、 Xml、または Json |
Microsoft.Data.SqlClientは、オブジェクト型、SqlTypeException、または宣言サイズに互換性がない場合、SqlDbType、ArgumentException、またはInvalidCastExceptionをスローします。 アップロードおよびダウンロードの完全な例については、 SqlClientストリーミングサポートをご覧ください。
パラメーター情報を派生させる
DeriveParametersSQL Serverでストアドプロシージャのパラメータメタデータをクエリし、コマンドの既存のパラメータコレクションを置き換えます:
using var command = new SqlCommand(
"dbo.uspGetEmployeeManagers",
connection);
command.CommandType = CommandType.StoredProcedure;
SqlCommandBuilder.DeriveParameters(command);
command.Parameters["@BusinessEntityID"].Value = 6;
DeriveParameters を呼び出すたびに、データベースとの追加の往復通信が必要です。 必要に応じて開発時にメタデータを導き出し、パフォーマンスに敏感なパスでパラメータを明示的に定義します。