そこで何が起こっているのですか?
Add
のいくつかのオーバーロードのパラメータリストを引用します 。これらは、SqlParameter
のコンストラクターオーバーロードに直接対応する便利なメソッドです。 クラス。基本的に、呼び出したコンビニエンスメソッドと同じシグネチャを持つコンストラクターを使用してパラメーターオブジェクトを構築し、SqlParameterCollection.Add(SqlParameter)
を呼び出します。 このように:
SqlParameter foo = new SqlParameter(parameterName, dbType, size);
this.Add(foo);
AddWithValue
似ていますが、さらに便利で、値を設定します。ただし、実際にはフレームワークの欠陥を解決するために導入されました。 MSDNを引用するには、
Add
の過負荷SqlParameterCollection.Add
とのあいまいさの可能性があるため、文字列を取り、オブジェクトは非推奨になりました。String
をとるオーバーロード およびSqlDbType
文字列とともに整数を渡すことが、パラメータ値または対応するSqlDbType
のいずれかであると解釈できる列挙値 価値。AddWithValue
を使用する 名前と値を指定してパラメータを追加するときはいつでも。
SqlParameter
のコンストラクターがオーバーロードします クラスは、インスタンスのプロパティを設定するための単なる便利なものです。これらはコードを短縮し、パフォーマンスにわずかな影響を与えます。コンストラクターはsetterメソッドをバイパスし、プライベートメンバーを直接操作する場合があります。違いがあれば、それほど大きくはありません。
どうすればよいですか?
次の点に注意してください(MSDNから)
双方向パラメータと出力パラメータ、および戻り値の場合、
Size
の値を設定する必要があります 。これは入力パラメーターには必要ありません。明示的に設定されていない場合、値は、パラメーター化されたステートメントが実行されるときに、指定されたパラメーターの実際のサイズから推測されます。
デフォルトのタイプはinputです。ただし、このようにサイズを推測できるようにし、パラメータオブジェクトをループでリサイクルする場合(パフォーマンスに関心があると言った場合)、サイズは最初の値で設定され、それ以降の値は次のようになります。クリップされました。明らかに、これは文字列などの可変長の値に対してのみ重要です。
ループ内で同じ論理パラメータを繰り返し渡す場合は、ループの外側にSqlParameterオブジェクトを作成し、適切なサイズにすることをお勧めします。 varcharのサイズを大きくしすぎても無害なので、正確な最大値を取得するのがPITAの場合は、列の予想よりも大きく設定してください。反復ごとに新しいオブジェクトを作成するのではなく、オブジェクトをリサイクルしているため、ループの期間中のメモリ消費量は低下する可能性があります。 特大サイズに少し興奮したとしても。
正直なところ、何千もの呼び出しを処理しない限り、これは大きな違いにはなりません。 AddWithValue
サイズの問題を回避して、新しいオブジェクトを作成します。短くて甘くてわかりやすいです。数千をループする場合は、私のアプローチを使用してください。そうでない場合は、AddWithValue
を使用してください コードをシンプルで保守しやすいものに保つため。
2008年はずっと前のことです
私がこれを書いてから数年で、世界は変わりました。新しい種類の日付があり、最近の日付の問題が拡大の影響について考えさせるまで、私の頭に浮かばなかった問題もあります。
用語に慣れていない人にとっては、拡大と縮小はデータ型変換の品質です。 intをdoubleに割り当てると、doubleの方が「幅が広い」ため、精度が低下することはありません。これは常に安全であるため、変換は自動的に行われます。これが、intをdoubleに割り当てることができる理由ですが、逆に明示的なキャストを行う必要があります。doubleからintへの変換は、精度が低下する可能性のあるナローイング変換です。
これは文字列に適用できます。NVARCHARはVARCHARよりも幅が広いため、VARCHARをNVARCHARに割り当てることができますが、逆の場合はキャストが必要です。 VARCHARは暗黙的にNVARCHARに拡張されるため、比較は機能しますが、これによりインデックスの使用が妨げられます!
C#文字列はUnicodeであるため、AddWithValueはNVARCHARパラメーターを生成します。もう一方の端では、VARCHAR列の値が比較のためにNVARCHARに拡張されます。これはクエリの実行を停止しませんが、インデックスが使用されるのを防ぎます。これは悪いです。
あなたはそれについて何ができますか?考えられる解決策は2つあります。
- パラメータを明示的に入力します。これは、AddWithValueがなくなることを意味します
- すべての文字列列タイプをNVARCHARに変更します。
VARCHARを捨てることはおそらく最良のアイデアです。これは、予測可能な結果を伴う単純な変更であり、ローカリゼーションストーリーを改善します。ただし、これをオプションとして使用できない場合があります。
最近は、直接ADO.NETをあまり使用していません。 Linq2Sqlが私の選択の武器になりました。この更新プログラムを作成するという行為により、この問題をどのように処理するのか疑問に思いました。 VARCHAR列を介したルックアップのためにデータアクセスコードをチェックしたいという突然の熱烈な欲求があります。
2019そして世界は再び
Linq2SqlはdotnetCoreで使用できないため、Dapperを使用しています。 [N] VARCHARの問題はまだ問題ですが、これまでのところ埋もれていません。 ADOも使用できると思いますので、その点で物事は一巡しました。