何が起こっているのですか?
のいくつかのオーバーロードのパラメーター リストを引用します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
インスタンス プロパティを設定するための単なる便利なものです。これらはコードを短縮しますが、パフォーマンスへの影響はわずかです。コンストラクターはセッター メソッドをバイパスし、プライベート メンバーを直接操作する可能性があります。差があれば大したことない。
私は何をすべきか?
以下に注意してください(MSDNから)
双方向および出力パラメータ、および戻り値については、 の値を設定する必要がありますSize
。これは入力パラメーターには必要ありません。明示的に設定されていない場合、パラメーター化されたステートメントが実行されるときに、指定されたパラメーターの実際のサイズから値が推測されます。
デフォルトのタイプは入力です。ただし、サイズをこのように推測できるようにし、パラメーター オブジェクトをループでリサイクルする場合 (パフォーマンスに関心があると言いました)、サイズは最初の値によって設定され、それよりも長い後続の値は次のようになります。切り取った。明らかに、これは文字列などの可変長の値に対してのみ重要です。
ループ内で同じ論理パラメーターを繰り返し渡す場合は、ループの外で SqlParameter オブジェクトを作成し、適切なサイズにすることをお勧めします。varchar のサイズを大きくしても問題はありません。そのため、正確な最大値を取得するのが PITA である場合は、列が予想されるよりも大きく設定してください。反復ごとに新しいオブジェクトを作成するのではなく、オブジェクトをリサイクルしているため、オーバーサイジングに少し興奮したとしても、ループ中のメモリ消費はおそらく減少します。
正直なところ、何千もの呼び出しを処理しない限り、どれも大きな違いはありません. AddWithValue
サイジングの問題を回避して、新しいオブジェクトを作成します。短くて甘くてわかりやすいです。数千をループする場合は、私のアプローチを使用してください。そうでない場合は、 を使用AddWithValue
して、コードをシンプルで維持しやすくします。
2008年は遠い昔
私がこれを書いてから数年で、世界は変わりました。新しい種類の日付があり、日付に関する最近の問題が拡大の意味について考えるまで、私の頭をよぎらなかった問題もあります。
拡大と縮小は、用語に慣れていない人にとっては、データ型変換の性質です。double に int を代入しても、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 は dotnet Core では使用できないため、Dapper を使用しています。[N]VARCHAR の問題はまだ解決されていませんが、埋もれているわけではありません。ADO を使用することもできると思いますので、その点で一巡しました。