Я использую кэш второго уровня NHibernate для сущности, первичный ключ которой является строковым столбцом. База данных нечувствительна к регистру, однако, когда я получаю объект, используя тот же Id, но с другим регистром, тогда NHibernate рассматривает объект как другой объект в кэше. Например, у меня есть таблица настроек со столбцом имени в качестве первичного ключа. Если я попытаюсь извлечь сущность с помощью session.Get<Setting>("TestMode")
, Get<Setting>("testmode")
или Get<Setting>("TESTMODE")
, то я попаду в базу данных 3 раза и поместу 3 отдельных сущности в кэш 2-го уровня. Если я затем что-то изменю в своем объекте Setting с помощью NHibernate, он обновит кэшированный объект, который фактически соответствует регистру на объекте, поскольку он хранится в базе данных (в данном случае тот, который называется «TestMode»). Проблема в том, что другие объекты все еще будут в кеше, но будут устаревшими.
Я понимаю, почему NHibernate рассматривает идентификаторы как регистрозависимые по умолчанию, но, насколько я могу найти, не существует способа установить регистронезависимость на уровне объекта или конфигурации. Можно ли это сделать, и если да, то как?
Если это поможет, я использую Fluent NHibernate. Мой Id столбец указан так:
Id(x => x.Name).GeneratedBy.Assigned().Column("Name");
UPDATE
Ниже приведены реализации Equals () и GetHashCode () из моей сущности Setting.
public override bool Equals(object obj)
{
if (obj == null)
return false;
if (obj is Setting)
{
if (object.ReferenceEquals(this, obj))
return true;
if (this.Name.Equals(((Setting)obj).Name, StringComparison.OrdinalIgnoreCase)) // Ignore case because our databases are case insensitive!
return true;
}
return false;
}
public override int GetHashCode()
{
return Name.ToUpperInvariant().GetHashCode();
}
ОБНОВЛЕНИЕ 2
Я профилировал с помощью NHibernate Profiler, и при выполнении поиска для «TestMode», «testmode», «TestMode», «Testmode», «TESTMODE» (в таком порядке) отображается только попадание в кэш для второго «TestMode». Он показывает «Настройка загрузки кэша 2-го уровня (TestMode / * id * /)», все остальные показывают SELECT ... FROM Setting setting0_ WHERE setting0_.Name = "testmode" (в любом случае, о котором просил вызов).
При нажатии на ссылку «См. 1 строку (и), полученную в результате этого оператора», он показывает строку с столбцом «Имя», имеющую правильный регистр «TestMode», поэтому он явно извлекает объект с правильным регистром для самого столбца, но кажется, что он определенно ассоциирует сущность с идентификатором, с которым была вызвана функция Get (). Это не похоже на нормальное поведение, но я не смог найти никакой информации об особенностях работы кэша 2-го уровня, а только об основах его использования из поваренной книги NHibernate.
Хотя я сомневаюсь, что это должно иметь значение, я использую HashtableCacheProvider для всех этих тестов. (для производства мы будем использовать платный провайдер кэширования)