データベースと C# コードの間にキャッシュ レイヤーを実装しています。アイデアは、クエリへのパラメーターに基づいて特定の DB クエリの結果をキャッシュすることです。データベースはデフォルトの照合順序を使用しています -SQL_Latin1_General_CP1_CI_AS
またはLatin1_General_CI_AS
のいずれかです。簡単なグーグル検索に基づいて、同等性と同等であり、並べ替えとは異なります。
データベースの照合が使用しているように、少なくとも等価テストとハッシュコード生成のために、同じ動作を提供できる .NET StringComparer が必要です。目標は、C# コードの .NET ディクショナリで StringComparer を使用して、特定の文字列キーが既にキャッシュにあるかどうかを判断できるようにすることです。
非常に単純化された例:
var comparer = StringComparer.??? // What goes here?
private static Dictionary<string, MyObject> cache =
new Dictionary<string, MyObject>(comparer);
public static MyObject GetObject(string key) {
if (cache.ContainsKey(key)) {
return cache[key].Clone();
} else {
// invoke SQL "select * from mytable where mykey = @mykey"
// with parameter @mykey set to key
MyObject result = // object constructed from the sql result
cache[key] = result;
return result.Clone();
}
}
public static void SaveObject(string key, MyObject obj) {
// invoke SQL "update mytable set ... where mykey = @mykey" etc
cache[key] = obj.Clone();
}
StringComparer がデータベースの照合順序と一致することが重要な理由は、偽陽性と偽陰性の両方がコードに悪影響を与えるためです。
2 つのキー A と B が異なるとデータベースが認識しているときに StringComparer がこれらのキーが等しいと言う場合、データベースにはこれら 2 つのキーを持つ 2 つの行が存在する可能性がありますが、A と B を要求された場合に 2 番目のキーが返されるのをキャッシュが防ぎます。 B の連続 - B の get が誤ってキャッシュにヒットし、A に対して取得されたオブジェクトを返すためです。
データベースが A と B が等しいと認識しているときに StringComparer が A と B が異なると言う場合、問題はより微妙ですが、それほど問題ではありません。両方のキーに対する GetObject 呼び出しは問題なく、同じデータベース行に対応するオブジェクトを返します。しかし、キー A を指定して SaveObject を呼び出すと、キャッシュが正しくないままになります。古いデータを持つキー B のキャッシュ エントリがまだ存在します。後続の GetObject(B) は古い情報を提供します。
したがって、私のコードが正しく機能するためには、 StringComparer が等価テストとハッシュコード生成のデータベースの動作に一致する必要があります。これまでの私のグーグル検索では、SQL 照合と .NET 比較が完全に同等ではないという事実について多くの情報が得られましたが、違いが何であるか、並べ替えの違いのみに限定されているかどうか、または見つけることが可能かどうかについての詳細はありません。汎用ソリューションが必要ない場合は、特定のSQL 照合順序と同等の StringComparer 。
(補足: キャッシング レイヤーは汎用的なものであるため、キーの性質や適切な照合順序について特定の仮定を立てることはできません。データベース内のすべてのテーブルは、同じ既定のサーバー照合順序を共有しています。一致する必要があるだけです。存在する照合順序)