最初に SqlParameter クラスが正しく記述されていれば、C# の null 値は DBNull.Value として処理されます。それは直観的であるため、もちろん、SqlParameter 値を null に設定することは、SqlParameterCollection から値を削除することと機能的に同等です。
このばかげた API 設計エラーを修正するには、SqlParameterCollection、String (パラメーター名)、および Object (パラメーター値) を受け取る独自の AddParameter メソッド (オーバーロードを使用) を作成します。
#region Add by Name/Value.
/// <summary>
/// Adds an input parameter with a name and value. Automatically handles conversion of null object values to DBNull.Value.
/// </summary>
/// <param name="parameters">SqlParameterCollection from an SqlCommand instance.</param>
/// <param name="name">The name of the parameter to add.</param>
/// <param name="value">The value of the parameter to add.</param>
private static void AddParameter( SqlParameterCollection parameters, string name, object value )
{
parameters.Add( new SqlParameter( name, value ?? DBNull.Value ) );
}
/// <summary>
/// Adds a parameter with a name and value. You specify the input/output direction. Automatically handles conversion of null object values to DBNull.Value.
/// </summary>
/// <param name="parameters">SqlParameterCollection from an SqlCommand instance.</param>
/// <param name="name">The name of the parameter to add.</param>
/// <param name="value">The value of the parameter to add. If null, this is automatically converted to DBNull.Value.</param>
/// <param name="direction">The ParameterDirection of the parameter to add (input, output, input/output, or return value).</param>
private static void AddParameter( SqlParameterCollection parameters, string name, object value, ParameterDirection direction )
{
SqlParameter parameter = new SqlParameter( name, value ?? DBNull.Value );
parameter.Direction = direction;
parameters.Add( parameter );
}
#endregion
#region Add by Name, Type, and Value.
/// <summary>
/// Adds an input parameter with a name, type, and value. Automatically handles conversion of null object values to DBNull.Value.
/// </summary>
/// <param name="parameters">SqlParameterCollection from an SqlCommand instance.</param>
/// <param name="name">The name of the parameter to add.</param>
/// <param name="type">Specifies the SqlDbType of the parameter.</param>
/// <param name="value">The value of the parameter to add. If null, this is automatically converted to DBNull.Value.</param>
private static void AddParameter( SqlParameterCollection parameters, string name, SqlDbType type, object value )
{
AddParameter( parameters, name, type, 0, value ?? DBNull.Value, ParameterDirection.Input );
}
/// <summary>
/// Adds a parameter with a name, type, and value. You specify the input/output direction. Automatically handles conversion of null object values to DBNull.Value.
/// </summary>
/// <param name="parameters">SqlParameterCollection from an SqlCommand instance.</param>
/// <param name="name">The name of the parameter to add.</param>
/// <param name="type">Specifies the SqlDbType of the parameter.</param>
/// <param name="value">The value of the parameter to add. If null, this is automatically converted to DBNull.Value.</param>
/// <param name="direction">The ParameterDirection of the parameter to add (input, output, input/output, or return value).</param>
private static void AddParameter( SqlParameterCollection parameters, string name, SqlDbType type, object value, ParameterDirection direction )
{
AddParameter( parameters, name, type, 0, value ?? DBNull.Value, direction );
}
#endregion
#region Add by Name, Type, Size, and Value.
/// <summary>
/// Adds an input parameter with a name, type, size, and value. Automatically handles conversion of null object values to DBNull.Value.
/// </summary>
/// <param name="parameters">SqlParameterCollection from an SqlCommand instance.</param>
/// <param name="name">The name of the parameter to add.</param>
/// <param name="type">Specifies the SqlDbType of the parameter.</param>
/// <param name="size">Specifies the size of the parameter for parameter types of variable size. Set to zero to use the default size.</param>
/// <param name="value">The value of the parameter to add. If null, this is automatically converted to DBNull.Value.</param>
private static void AddParameter( SqlParameterCollection parameters, string name, SqlDbType type, int size, object value )
{
AddParameter( parameters, name, type, size, value ?? DBNull.Value, ParameterDirection.Input );
}
/// <summary>
/// Adds a parameter with a name, type, size, and value. You specify the input/output direction. Automatically handles conversion of null object values to DBNull.Value.
/// </summary>
/// <param name="parameters">SqlParameterCollection from an SqlCommand instance.</param>
/// <param name="name">The name of the parameter to add.</param>
/// <param name="type">Specifies the SqlDbType of the parameter.</param>
/// <param name="size">Specifies the size of the parameter for parameter types of variable size. Set to zero to use the default size.</param>
/// <param name="value">The value of the parameter to add. If null, this is automatically converted to DBNull.Value.</param>
/// <param name="direction">The ParameterDirection of the parameter to add (input, output, input/output, or return value).</param>
private static void AddParameter( SqlParameterCollection parameters, string name, SqlDbType type, int size, object value, ParameterDirection direction )
{
SqlParameter parameter;
if (size < 1)
parameter = new SqlParameter( name, type );
else
parameter = new SqlParameter( name, type, size );
parameter.Value = value ?? DBNull.Value;
parameter.Direction = direction;
parameters.Add( parameter );
}
#endregion
ご覧のとおり、値が既にオブジェクトとして型指定されているメソッド (およびオーバーロード) 内で、"value ?? DBNull.Value" ステートメントを使用して null = DBNull.Value ルールを適用します。
これで、値のない null オブジェクト参照または null 許容型を AddParameter メソッドに渡すと、DBNull.Value がクエリに渡されるという、予想どおりの直感的な動作が得られます。
なぜAPIがそのまま実装されたのか想像できません。パラメーターを無視したい場合は、それを追加せず、その値をnullに設定するからです。そもそも追加しないか、SqlParameterCollection から削除します。パラメータを追加し、その値を設定した場合 (null に設定されていても)、クエリで使用されると予想されます。null は null 値を意味すると予想されます。
パフォーマンス上の理由から「正しい」方法で実装しなかったと聞いたことがありますが、SqlParameterCollection.AddWithValue メソッドを呼び出すとすべてがオブジェクトに変換され、値のない Nullable インスタンスが null に変換されるため、実証されているようにばかげています。 object は C# 言語の本質的な部分であり、パフォーマンスにまったく影響しません。マイクロソフトは本当にこれを修正する必要があります。