0

子エンティティが袋としてマップされ、子エンティティと親の間のキーが文字列であるエンティティをロードしようとすると、キーの大文字と小文字の区別が親のIDプロパティと一致しない場合は移入されます。NHibernateバッグを大文字と小文字を区別しないキーでマッピングする方法

もし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です。

どのようにマップすることができますか?を修正して、大文字小文字に関係なく常にロードされますか?

+0

基本となるデータベースは何ですか? – Fran

+0

MSSQL 2014.私はNHProfilerを使用しました。私は、SQL Serverが両方のケースのデータを返すことを証明できるので、セッションまたはキャッシュに問題があるようです。 – neoscribe

答えて

0

イベントリスナーを使用して問題を解決しようと数日後に、デバッグすると、NHibernateにバグがあります。

実際のNHibernateソースを変更し、再構築して再リンクすることで、この問題を解決できました。 私が使用したテクニックでは、実際のエンティティキーは変更されていません。そのため、データベースの出入り時と同じようにケースが保持されます。

のNHibernateはエンティティをロードすると、「キー」は基本的にセッションまたはエンティティのキ​​ャッシュとその関連を表したIDictionary <>に保存され、テストされているだけでマーカーあるが作成され、依存コレクション。この"キー"は、大文字と小文字を区別しない比較を行うのに十分スマートではありませんでした。そのためには、ハッシュコードを修正してEquals()を調整して、大文字と小文字を区別しない比較を行わなければならなかったので、キー内の大文字と小文字がテスト値と異なる場合、常にヒットします。

あなたはNHibernateのを構築し、それが修正されるまで、ハイテク債務を所有して慣れている場合は、ここで私のパッチは次のとおりです。

変更EntityKey.cs、CollectionKey.cs、およびCacheKey.cs

  1. GetHashCode() - キーの大文字と小文字を区別せずに一貫したハッシュコードを返す必要があります。そうでない場合、ケースが異なる場合、Equals()はとなり、は呼び出されません。
  2. 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

+0

バグではないとして破棄されました。データベースは大文字と小文字を区別することもできます。 [NH-3833](https://nhibernate.jira.com/browse/NH-3833)のAlexanderが説明しているように、自分のキーをカスタムタイプにマッピングすることで、独自の等価セマンティックを実装することができます。 –

+0

クール、ありがとう、私はそれが動作し、結果を投稿する場合は表示されます。 http://nhibernate.info/blog/2009/10/15/mapping-different-types-iusertype.html – neoscribe

関連する問題