在尝试使用事件侦听器解决问题几天后,调试,结果发现 NHibernate 中存在错误。
我能够通过更改实际的 NHibernate 源、重建和重新链接来解决问题。
我使用的技术使实际的实体键保持不变,因此保留了它来自或进入数据库时的大小写。
当 NHibernate 加载一个实体时,会创建一个 "key",它基本上只是一个 标记,它存储在一个 IDictionary 中并进行测试,它代表会话或实体及其相关的依赖集合的缓存。这个 “key” 不够聪明,无法进行不区分大小写的比较。为了做到这一点,我必须修改哈希码并调整 Equals() 以进行不区分大小写的比较,这样如果键中的大小写与测试值不同,它总是会受到影响。
如果您愿意构建 NHibernate 并拥有技术债务直到它被修复,这里是我的补丁:
修改 EntityKey.cs、CollectionKey.cs 和 CacheKey.cs
-
GetHashCode() - 无论键的大小写如何,都需要返回一致的哈希码。否则,当情况不同时,Equals() 将 NEVER 被调用。
-
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。