如何使用不区分大小写的键映射NHibernate包

时间:2016-09-20 00:03:51

标签: c# nhibernate one-to-many nhibernate-mapping case-insensitive

当我尝试加载一个将子实体映射为包的实体,并且子实体和父实体之间的键是一个字符串时,如果该键的大小写与父类不匹配,则不会填充生成的包。身份证。

如果 Office.ID ==“ MyOffice PromotionalContent.ContextKey ==“ myoffice ,即使NHProfiler显示它是由数据库返回的,该集合也不会加载促销

如果 Office.ID ==“ MyOffice ”和* PromotionalContent.ContextKey ==“ MyOffice ”,收藏品负载

    <class name="Office" table="Office" lazy="true">
        <id name="ID" column="OfficeNum">
            <generator class="assigned" />
        </id>
      <property name="Name" column="OfficeName" />
      <property name="PhoneNumber" column="PhoneNum" />
      <bag name="Promotions" lazy="true" where="ContextType='Office'"  >
        <key column="ContextKey"/>
        <one-to-many  class="PromotionalContent"/>
      </bag>...

这是NHibernate 4.0.3版。

我如何映射它,或者修复它以便无论如何总是加载?

1 个答案:

答案 0 :(得分:0)

使用事件监听器尝试解决问题几天后,调试结果发现NHibernate存在一个错误。

我能够通过更改实际的NHibernate源,重建和重新链接来解决问题。 我使用的技术使实际的实体键保持不变,因此保留了它来自或进入数据库时​​的情况。

当NHibernate加载实体时,会创建&#34;键&#34; ,它基本上只是一个标记,它在IDictionary中存储和测试&lt;&gt; ;表示会话或实体及其相关依赖集合的缓存。这个&#34; key&#34; 不够聪明,不能进行不区分大小写的比较。为了做到这一点,我必须修改哈希码并调整Equals()以进行不区分大小写的比较,这样如果密钥中的大小写与测试值不同,它总是会被命中。

如果你习惯于建立NHibernate并拥有技术债务,直到它被修复,这是我的补丁:

修改EntityKey.cs,CollectionKey.cs和CacheKey.cs

  1. GetHashCode() - 无论密钥是什么情况,都需要返回一致的哈希码。否则,当案例不同时,Equals()将从不调用。
  2. Equals() - 无论如何都需要返回true。否则,您的实体和/或其子集将会被遗漏。
  3. 我通过简单地使用大写进行比较来欺骗,而不是做不区分大小写的比较。

    示例代码:

    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