イベントリスナーを使用して問題を解決しようと数日後に、デバッグすると、NHibernateにバグがあります。
実際のNHibernateソースを変更し、再構築して再リンクすることで、この問題を解決できました。 私が使用したテクニックでは、実際のエンティティキーは変更されていません。そのため、データベースの出入り時と同じようにケースが保持されます。
のNHibernateはエンティティをロードすると、「キー」は基本的にセッションまたはエンティティのキャッシュとその関連を表したIDictionary <>に保存され、テストされているだけでマーカーあるが作成され、依存コレクション。この"キー"は、大文字と小文字を区別しない比較を行うのに十分スマートではありませんでした。そのためには、ハッシュコードを修正してEquals()を調整して、大文字と小文字を区別しない比較を行わなければならなかったので、キー内の大文字と小文字がテスト値と異なる場合、常にヒットします。
あなたはNHibernateのを構築し、それが修正されるまで、ハイテク債務を所有して慣れている場合は、ここで私のパッチは次のとおりです。
変更EntityKey.cs、CollectionKey.cs、およびCacheKey.cs
- GetHashCode() - キーの大文字と小文字を区別せずに一貫したハッシュコードを返す必要があります。そうでない場合、ケースが異なる場合、Equals()はとなり、は呼び出されません。
- Equals() - 大文字と小文字を区別せずにtrueを返す必要があります。そうしないと、エンティティおよび/またはその子コレクションが欠落します。
大文字と小文字を区別しない比較を行うのではなく、単に大文字で比較するのは嫌です。
サンプルコード:
EntityKey.cs
public override bool Equals(object other)
{
var otherKey = other as EntityKey;
if(otherKey==null) return false;
if (Identifier is string && otherKey.Identifier is string)
{
object thiskeySanitized = ((string)Identifier).ToUpper();
object thatkeySanitized = ((string)otherKey.Identifier).ToUpper();
return otherKey.rootEntityName.Equals(rootEntityName) && identifierType.IsEqual(thatkeySanitized, thiskeySanitized, entityMode, factory);
}
return
otherKey.rootEntityName.Equals(rootEntityName)
&& identifierType.IsEqual(otherKey.Identifier, Identifier, entityMode, factory);
}
private int GenerateHashCode()
{
int result = 17;
object sanitizedIdentifier = (identifier is string) ? ((string) identifier).ToUpper() : identifier;
unchecked
{
result = 37 * result + rootEntityName.GetHashCode();
result = 37 * result + identifierType.GetHashCode(sanitizedIdentifier, entityMode, factory);
}
return result;
}
CollectionKey.cs
public override bool Equals(object obj)
{
CollectionKey that = (CollectionKey)obj;
if (this.key is string && that.key is string)
{
object thiskeySanitized = ((string)this.key).ToUpper();
object thatkeySanitized = ((string)that.key).ToUpper();
return that.role.Equals(role) && keyType.IsEqual(thatkeySanitized, thiskeySanitized, entityMode, factory);
}
return that.role.Equals(role) && keyType.IsEqual(that.key, key, entityMode, factory);
}
private int GenerateHashCode()
{
int result = 17;
unchecked
{
result = 37 * result + role.GetHashCode();
object sanitizedIdentifier = (key is string) ? ((string)key).ToUpper() : key;
result = 37 * result + keyType.GetHashCode(sanitizedIdentifier, entityMode, factory);
}
return result;
}
CacheKey.cs
public CacheKey(object id, IType type, string entityOrRoleName, EntityMode entityMode, ISessionFactoryImplementor factory)
{
key = id;
this.type = type;
this.entityOrRoleName = entityOrRoleName;
this.entityMode = entityMode;
object sanitizedIdentifier = (key is string) ? ((string)key).ToUpper() : key;
hashCode = type.GetHashCode(sanitizedIdentifier, entityMode, factory);
}
public override bool Equals(object obj)
{
CacheKey that = obj as CacheKey;
if (that == null) return false;
if (key is string && that.key is string)
{
object thiskeySanitized = ((string)key).ToUpper();
object thatkeySanitized = ((string)that.key).ToUpper();
return entityOrRoleName.Equals(that.entityOrRoleName) && type.IsEqual(thiskeySanitized, thatkeySanitized, entityMode);
}
return entityOrRoleName.Equals(that.entityOrRoleName) && type.IsEqual(key, that.key, entityMode);
}
問題は2015年にNHibernateチームに報告されました。https://nhibernate.jira.com/browse/NH-3833。
基本となるデータベースは何ですか? – Fran
MSSQL 2014.私はNHProfilerを使用しました。私は、SQL Serverが両方のケースのデータを返すことを証明できるので、セッションまたはキャッシュに問題があるようです。 – neoscribe