Я реализую слой кэширования между моей базой данных и кодом С#. Идея состоит в том, чтобы кэшировать результаты определенных запросов БД на основе параметров запроса. В базе данных используется сортировка по умолчанию - либо SQL_Latin1_General_CP1_CI_AS
, либо Latin1_General_CI_AS
, которые, как мне кажется, основаны на некотором кратком поиске, эквивалентны для равенства, просто разные для сортировки.
Мне нужен .NET StringComparer, который может дать мне такое же поведение, по крайней мере, для тестирования равенства и генерации hashcode, поскольку используется сортировка базы данных. Цель состоит в том, чтобы иметь возможность использовать StringComparer в словаре .NET в коде С#, чтобы определить, находится ли конкретный строковый ключ в кеше или нет.
Действительно упрощенный пример:
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 соответствовала настройке базы данных, заключается в том, что и ложные срабатывания, и ложные негативы будут иметь плохие последствия для кода.
Если StringComparer говорит, что два ключа A и B равны, когда база данных считает, что они различны, тогда в базе данных могут быть две строки с этими двумя ключами, но кеш будет препятствовать тому, чтобы второй возвращался, если его спросили для A и B подряд - потому что get для B неправильно попадет в кеш и вернет объект, который был получен для A.
Проблема более тонкая, если StringComparer говорит, что A и B различаются, когда база данных считает, что они равны, но не менее проблематичны. Вызов GetObject для обоих ключей будет прекрасным и возвращать объекты, соответствующие одной и той же строке базы данных. Но тогда вызов SaveObject с ключом A оставил бы кеш неправильным; все равно будет запись кэша для ключа B, в которой есть старые данные. Последующий GetObject (B) предоставит устаревшую информацию.
Итак, чтобы мой код работал правильно, мне нужно, чтобы StringComparer соответствовал поведению базы данных для тестирования равенства и генерации хэш-кода. До сих пор мой googling дал много информации о том, что SQL-сопоставления и сравнения .NET не совсем эквивалентны, но нет подробностей о том, каковы различия, ограничены ли они только различиями в сортировке или можно ли найти StringComparer, который эквивалентен специфической сортировке SQL, если универсальное решение не требуется.
(Боковое примечание - слой кэширования является общим назначением, поэтому я не могу сделать конкретные предположения о том, что характер ключа и что такое сопоставление будет уместно. Все таблицы в моей базе данных имеют одинаковый набор настроек по умолчанию. необходимо сопоставить сортировку, поскольку она существует)