10

ストアド プロシージャを呼び出す C# ルーチンを作成しています。私が渡しているパラメーター リストでは、値の 1 つが合法的に null になる可能性があります。そこで、次のような行を使用すると思いました。

cmd.Parameters.Add(new SqlParameter("@theParam", theParam ?? DBNull.Value));

残念ながら、これは次のエラーを返します。

CS0019: 演算子 '??' タイプ「string」および「System.DBNull」のオペランドには適用できません

さて、これは十分に明確に思えますが、その背後にある理論的根拠がわかりません。なぜこれがうまくいかないのでしょうか?(そして、何かがうまくいかない理由がわからなくても、それはうまくいかないということではなく、私のやり方が間違っているということがよくあります。)

本当にこれをより長い if-then ステートメントに拡張する必要がありますか?

EDIT:(余談ですが、「null」をそのまま使用することを提案している人には、うまくいきません。最初はnullもDBNullに自動変換されると考えていましたが、明らかにそうではありません。(誰が知っていましたか?))

4

10 に答える 10

16

そうじゃない、いいえ。タイプが一致する必要があります。同じことが三元にも当てはまります。

さて、「一致」とは、それらが同じである必要があるという意味ではありません。ただし、それらは代入に対応している必要があります。基本的に:同じ継承ツリー内。

これを回避する 1 つの方法は、文字列をオブジェクトにキャストすることです。

var result = (object)stringVar ?? DBNull.Value;

しかし、私はこれが好きではありません。それは、型を正しくするために SqlParameter コンストラクターにもっと依存していることを意味するからです。代わりに、次のようにするのが好きです。

cmd.Parameters.Add("@theParam", SqlDbTypes.VarChar, 50).Value = theParam;
// ... assign other parameters as well, don't worry about nulls yet

// all parameters assigned: check for any nulls
foreach (var p in cmd.Parameters) 
{ 
    if (p.Value == null) p.Value = DBNull.Value; 
}

また、パラメーターの型を明示的に宣言したことにも注意してください。

于 2009-10-09T19:54:35.427 に答える
5
new SqlParameter("@theParam", (object)theParam ?? DBNull.Value)
于 2009-10-09T19:49:43.970 に答える
3

?? 演算子は、null でない場合は左側のオペランドを返し、それ以外の場合は右側のオペランドを返します。しかし、あなたの場合、それらは異なるタイプであるため、機能しません。

于 2009-10-09T19:50:10.520 に答える
2

null 合体演算子を使用できない理由は、1 つの型を返す必要があり、複数の型を提供しているためです。theParamは文字列です。System.DbNullDbNull.Value型の静的インスタンスへの参照です。これは、その実装がどのように見えるかです。

public static readonly DBNull Value = new DBNull(); 
//the instantiation is actually in the 
//static constructor but that isn't important for this example

では、NullCoalesce メソッドがあるとしたら、その戻り値の型は何でしょうか? System.String と System.DbNull の両方にすることはできません。どちらか一方、または共通の親型である必要があります。

したがって、このタイプのコードにつながります。

cmd.Parameters.Add(
    new SqlParameter("@theParam", (object)theParam ?? (object)DBNull.Value)
);
于 2009-10-09T19:51:38.010 に答える
2

Null 合体演算子は、同じタイプのデータのみを使用します。SqlParamater に NULL を送信することはできません。これにより、Sql Server はパラメーターを指定しなかったと判断します。

使用できます

new SqlParameter("@theParam", (object)theParam ?? (object)DBNull.Value)

または、null が見つかったときに DBNull を返す関数を作成することもできます。

public static object GetDataValue(object o)
{
    if (o == null || String.Empty.Equals(o))
        return DBNull.Value;
    else
        return o;
}

そして、電話する

new SqlParameter("@theParam", GetDataValue(theParam))
于 2009-10-09T19:56:33.393 に答える
1

入ってくる変数を宣言するとき、ストアド プロシージャで var を null に設定し、それを csharp コードから渡さないと、sql からデフォルト値が取得されます。

@theParam as varchar(50) = null

そしてあなたのcsharpで

if (theParam != null)
    cmd.Parameters.Add(new SqlParameter("@theParam", theParam));

これは、通常、オプションやデフォルトの値をストアド プロシージャに渡す方法です。

于 2009-10-09T20:16:01.310 に答える
0

次の構文を使用します。

(オブジェクトとしての theParam) ?? (オブジェクトとしての DBNull.Value)

この場合、演算子の両方の部分 ?? は同じタイプです。

于 2009-10-09T20:07:22.343 に答える
0

null を SqlParameter コンストラクターに渡すだけで DBNull.Value として送信されると確信しています... DB アクセスに EnterpriseLibraries を使用しているため、間違っている可能性がありますが、 null は問題ありません。

于 2009-10-09T19:49:20.870 に答える
0

cmd.Parameters.Add(new SqlParameter("@theParam", (theParam == null) ? DBNull.Value : theParam));

于 2009-10-09T19:51:16.687 に答える
-1

あなたの質問に対する具体的な答えはわかりませんが、これはどうですか?

string.IsNullOrEmpty(theParam) ? DBNull.Value : theParam

または空白で問題ない場合

(theParam == null) ? DBNull.Value : theParam
于 2009-10-09T19:49:20.960 に答える