2009-08-28 11 views
3

私はFluent NHibernateバージョン1.0.0.579(この時点で最新バージョン)を使用しています。私は抽象的なアクティビティクラスといくつかの継承クラスを持っています。 DummyActivity。それらのすべてが同じテーブルアクティビティを使用し、それらのすべてがプロジェクトのマッピングを指す整数型に基づく識別子値を持ちます(データベース内のFKではありません)。Fluent NHibernateテーブルごとの階層マッピングの問題

私たちは、このようなマッピング建て:生成されたのhbm.xmlファイルがある

public class ActivityMap : ClassMap<Activity> 
    { 
     public ActivityMap() 
     { 
      Table("Activities"); 
      Id(x => x.Id).Column("ID").GeneratedBy.Guid(); 
      Map(x => x.ActivityName).Not.Nullable().Length(50); 
      HasMany(x => x.ActivityParameters) 
       .KeyColumn("ActivityID") 
       .AsMap<string>(idx => idx.Column("ParameterName"), elem => elem.Column("ParameterValue")) 
       .Not.LazyLoad() 
       .Cascade.Delete() 
       .Table("ActivityParameters"); 

      DiscriminateSubClassesOnColumn<int>("ActivityType") 
       .SubClass<DummyActivity>(1, c => { }); 
     } 
    } 

を:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true"> 
    <class xmlns="urn:nhibernate-mapping-2.2" name="***.Activity, ***, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="Activities"> 
    <id name="Id" type="System.Guid, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <column name="ID" /> 
     <generator class="guid" /> 
    </id> 
    <discriminator column="ActivityType" type="Int32" insert="true" not-null="true" /> 
    <property name="ActivityName" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <column name="ActivityName" length="50" not-null="true" /> 
    </property> 
    <map cascade="delete" lazy="false" name="ActivityParameters" table="ActivityParameters"> 
     <key> 
     <column name="ActivityID" /> 
     </key> 
     <index type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <column name="ParameterName" /> 
     </index> 
     <element type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <column name="ParameterValue" /> 
     </element> 
    </map> 
    <subclass name="***.DummyActivity, ***, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="1" /> 
    </class> 
</hibernate-mapping> 

は私の信念によると、これは、有効なのhbm.xmlファイルと同様で同じに見えますNHibernate公式の公式文書に与えられた例を持つ構造、すなわち

<class name="IPayment" table="PAYMENT"> 
<id name="Id" type="Int64" column="PAYMENT_ID"> 
<generator class="native"/> 
</id> 
<discriminator column="PAYMENT_TYPE" type="String"/> 
<property name="Amount" column="AMOUNT"/> 
... 
<subclass name="CreditCardPayment" discriminator-value="CREDIT"> 
... 
</subclass> 
<subclass name="CashPayment" discriminator-value="CASH"> 
... 
</subclass> 
<subclass name="ChequePayment" discriminator-value="CHEQUE"> 
... 
</subclass> 
</class> 

マッピングに間違いがありますか?また、誰かが(、

public class ActivityMap : ClassMap<Activity> 
    { 
     public ActivityMap() 
     { 
      Table("Activities"); 
      Id(x => x.Id).Column("ID").GeneratedBy.Guid(); 
      Map(x => x.ActivityName).Not.Nullable().Length(50); 
      HasMany(x => x.ActivityParameters) 
       .KeyColumn("ActivityID") 
       .AsMap<string>(idx => idx.Column("ParameterName"), elem => elem.Column("ParameterValue")) 
       .Not.LazyLoad() 
       .Cascade.Delete() 
       .Table("ActivityParameters"); 

      DiscriminateSubClassesOnColumn<int>("ActivityType"); 
     } 
    } 

public class DummyActivityMap : SubClass<DummyActivity> 
{ 
    ///discriminator value here how??? 
} 

のようなものを識別カラムとサブクラスを使用して?)私に流暢が推奨する新しい実装を指すことができます

スタックトレースが

[FormatException: Input string was not in a correct format.] 
    System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal) +7469351 
    System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info) +119 
    NHibernate.Type.Int32Type.FromStringValue(String xml) +36 
    NHibernate.Type.Int32Type.StringToObject(String xml) +10 
    NHibernate.Persister.Entity.SingleTableEntityPersister..ctor(PersistentClass persistentClass, ICacheConcurrencyStrategy cache, ISessionFactoryImplementor factory, IMapping mapping) +7824 

[MappingException: Could not format discriminator value to SQL string of entity ***.Activity] 
    NHibernate.Persister.Entity.SingleTableEntityPersister..ctor(PersistentClass persistentClass, ICacheConcurrencyStrategy cache, ISessionFactoryImplementor factory, IMapping mapping) +8183 
    NHibernate.Persister.PersisterFactory.CreateClassPersister(PersistentClass model, ICacheConcurrencyStrategy cache, ISessionFactoryImplementor factory, IMapping cfg) +68 
    NHibernate.Impl.SessionFactoryImpl..ctor(Configuration cfg, IMapping mapping, Settings settings, EventListeners listeners) +1468 
    NHibernate.Cfg.Configuration.BuildSessionFactory() +87 
    FluentNHibernate.Cfg.FluentConfiguration.BuildSessionFactory() in d:\Builds\FluentNH\src\FluentNHibernate\Cfg\FluentConfiguration.cs:93 

[FluentConfigurationException: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail. 

] 
    ***.Container.ConfigureNHibernate() in ***.Unity\Container.cs:92 
    ***.Container.ConfigureContainer() in ***.Unity\Container.cs:60 
    ***.Container.GetInstance() in ***.Unity\Container.cs:45 
    ***.Global.CreateContainer() in ***\Global.asax.cs:72 
    ***.Global.Application_Start(Object sender, EventArgs e) in ***\Global.asax.cs:44 

答えて

2

私は列挙型の場合に考え出しました。

public enum ActivityType 
{ 
    [EnumKey("1")] 
    [EnumDescription("ImportFromFile")] 
    ImportFromFile, 
} 

EnumKeyとEnumDescriptionは(人気の)拡張メソッドされている場合、私は

public abstract class Activity 
    { 
     public virtual Guid Id { get; set; } 
     public virtual ActivityExecutionResult ExecutionResult { get; private set; } 

     public virtual ActivityExecutionStatus ExecutionStatus {get;private set;} 

     public abstract ActivityExecutionStatus Execute(); 

     public virtual string ActivityName { get; private set; } 

     public virtual IDictionary<string, string> ActivityParameters { get; private set; } 

     public virtual ActivityType ActivityType { get; private set; } 
    } 

のような活動を再定義し、マッピングファイルは、次のようになります:

public class ActivityMap : ClassMap<Activity> 
    { 
     public ActivityMap() 
     { 
      Table("Activities"); 
      Id(x => x.Id).Column("ID").GeneratedBy.Guid(); 
      Map(x => x.ActivityName).Not.Nullable().Length(50); 
      Map(x => x.ActivityType).CustomType<int>().Column("ActivityType").Not.Nullable(); 
      HasMany(x => x.ActivityParameters) 
       .KeyColumn("ActivityID") 
       .AsMap<string>(idx => idx.Column("ParameterName"), elem => elem.Column("ParameterValue")) 
       .Not.LazyLoad() 
       .Cascade.Delete() 
       .Table("ActivityParameters"); 

      DiscriminateSubClassesOnColumn("ActivityType"); 
     } 
    } 

    public class ImportActivityFromFileMap : SubclassMap<ImportActivityFromFile> 
    { 
     public ImportActivityFromFileMap() 
     { 
      DiscriminatorValue(ActivityType.ImportFromFile.GetKey()); 
     } 
    } 
この列挙型を考慮

生成されたhbmファイルは次のようになります。

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true"> 
    <class xmlns="urn:nhibernate-mapping-2.2" name="***.Activity, ***, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="Activities"> 
    <id name="Id" type="System.Guid, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <column name="ID" /> 
     <generator class="guid" /> 
    </id> 
    <discriminator column="ActivityType" type="String" insert="true" not-null="true" /> 
    <property name="ActivityName" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <column name="ActivityName" length="50" not-null="true" /> 
    </property> 
    <property name="ActivityType" type="Int32"> 
     <column name="ActivityType" not-null="true" /> 
    </property> 
    <map cascade="delete" lazy="false" name="ActivityParameters" table="ActivityParameters"> 
     <key> 
     <column name="ActivityID" /> 
     </key> 
     <index type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <column name="ParameterName" /> 
     </index> 
     <element type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <column name="ParameterValue" /> 
     </element> 
    </map> 
    <subclass name="***.ImportActivityFromFile, ***, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="1" /> 
    </class> 
</hibernate-mapping> 

これは魅力的に機能します。

0

あなたはそれを理解しましたですどのように整数の代わりにenumを使用するのですか?整数では、記述したように機能しますが、列挙型では機能しません。私がそれらをintにキャストしたとしても、

などの DiscriminatorValue((int)SomeEnum.SomeVaue))

+0

いいえ、私はしませんでした。http://code.google.com/p/fluent-nhibernate/issues/detail?id=240を見てください。オープンな問題です。質問をしましたhttp://groups.google.com/group/fluent-nhibernate/browse_thread/thread/4d38111df91e72b9こちらもご覧ください。列挙型のような整数を使用していますが、すぐに採用するかもしれません。 – DaeMoohn

+0

私はコンセプトを働かせて、enumで試してみるつもりです。私はあなたにn答え。 – DaeMoohn

+0

最初のリンクが壊れています。 – Astaar

0

私が思いついた別の実装を紹介します。これにより

public class SmartEnumMapping<T> : IUserType 
    { 
     #region IUserType Members 

     public object Assemble(object cached, object owner) 
     { 
      return cached; 
     } 

     public object DeepCopy(object value) 
     { 
      return value; 
     } 

     public object Disassemble(object value) 
     { 
      return value; 
     } 

     public int GetHashCode(object x) 
     { 
      return x.GetHashCode(); 
     } 

     public bool IsMutable 
     { 
      get { return false; } 
     } 

     public new bool Equals(object x, object y) 
     { 
      return object.Equals(x, y); 
     } 

     public object NullSafeGet(System.Data.IDataReader rs, string[] names, object owner) 
     { 
      int index0 = rs.GetOrdinal(names[0]); 
      if (rs.IsDBNull(index0)) 
      { 
       return null; 
      } 
      string key = rs.GetString(index0); 
      return EnumExtensions.EnumParseKey<T>(key, false, true); 
     } 

     public void NullSafeSet(System.Data.IDbCommand cmd, object value, int index) 
     { 
      if (value == null) 
      { 
       ((IDbDataParameter)cmd.Parameters[index]).Value = DBNull.Value; 
      } 
      else 
      { 
       T enumValue = (T)Enum.Parse(typeof(T), value.ToString()); 
       ((IDbDataParameter)cmd.Parameters[index]).Value = enumValue.GetKey(); 
      } 
     } 

     public object Replace(object original, object target, object owner) 
     { 
      return original; 
     } 

     public Type ReturnedType 
     { 
      get { return typeof(T); } 
     } 

     public global::NHibernate.SqlTypes.SqlType[] SqlTypes 
     { 
      get { return new SqlType[] { SqlTypeFactory.GetString(4096) }; } 
     } 

     #endregion 
} 

、マッピングは

Map(x => x.ActivityType).CustomType<SmartEnumMapping<ActivityType>>().Column("ActivityType").Not.Nullable(); 

ActivityTypeをコードで、私は "ActivityType.das" を使用することができ、これにより

public enum ActivityType 
    { 
     [EnumKey("1")] 
     [EnumDescription("dada")] 
     dad, 

     [EnumKey("2")] 
     [EnumDescription("da")] 
     ImportCalculAtasateSfarsitLuna, 

     [EnumKey("3")] 
     [EnumDescription("da")] 
     das, 

     } 

のように見えますが、永続化するとき、それはなりました「3」を維持した。再度、データベースから読み込むと、私は "3"を読みますが、私はそれを "ActivityType"に変換します。DAS」。

私は、これは、前の回答で述べた行動を説明し、より適切な答えですね。

もう一度、EnumKey、EnumDescription、EnumParseKeyなどが簡単にインターネット上で見つけることができるものです

関連する問題