2009-08-28 71 views
3

我使用的流利NHibernate版本1.0.0.579(最新版本在這個日期)。我有一個抽象的Activity類和幾個繼承類,例如。 DummyActivity。它們都使用相同的表活動,並且它們都具有基於指向項目中的映射(而非數據庫中的FK)的整數類型的鑑別器值。流利的NHibernate表每層次映射問題

我們建立這樣的映射:

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 => { }); 
     } 
    } 

生成的hbm.xml文件是:

<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

難道你看着辦吧如何使用枚舉而不是整數?整數的作用就像你描述的一樣,但是它不包含枚舉。即使我把它們投到int

E.g. 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 2009-08-28 11:07:13

+0

只要我會有一個概念工作,我會嘗試一個枚舉,我會給你一個ñ答案。 – DaeMoohn 2009-08-28 11:13:38

+0

您的第一個鏈接已損壞。 – Astaar 2013-03-18 14:58:40

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看起來像

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

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

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

     } 

有了這個,在我的代碼可以使用 「ActivityType.das」,但堅持的時候,它是堅持「3」。再次,從數據庫讀取時,我讀了「3」,但我將它轉換爲「ActivityType」。DAS」。

我想這是一個比較合適的回答,解釋在前面的回答中提到的行爲。

再次,EnumKey,EnumDescription,EnumParseKey等都是東西,可以在互聯網上很容易被發現