經過幾天嘗試解決使用事件偵聽器的問題,調試後發現NHibernate中存在一個錯誤。
我能夠通過改變實際的NHibernate源代碼,重建和重新鏈接來解決問題。 我使用的技術使實際的實體鍵保持原樣,因此保留大小寫的情況,因爲它來自或進入數據庫。
當NHibernate的加載一個實體,「鑰匙」被創建基本上是一個標記存儲和測試一個IDictionary <>表示會話或實體的高速緩存及其相關,依賴集合。這「關鍵」是不夠智能做不區分大小寫的比較。爲了做到這一點,我必須修改哈希碼並調整Equals()以進行不區分大小寫的比較,以便在密鑰內的情況與測試值不同的情況下始終得到匹配。
如果您熟悉建築NHibernate和擁有高科技的債務,直到它是固定的,這裏是我的補丁:
修改EntityKey.cs,CollectionKey.cs和CacheKey.cs
- GetHashCode() - 無論密鑰的情況如何,都需要返回一致的哈希碼。否則,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