为层次结构中的多类提供流畅的NHibernate表继承(TPH)映射

时间:2013-05-15 11:13:13

标签: c# nhibernate orm fluent-nhibernate mapping

大家好,

我正在努力解决一个流利的NHibernate问题。 我在我的解决方案中有以下类结构模板:

class OneClass
{
    public virtual string OneProp {get; set;}
}

class TwoClass : OneClass
{
     public virtual string TwoProp {get; set;}
}

class ThreeClass : TwoClass
{
     public virtual string ThreeProp {get; set;}
}

我想为我的类使用table-per-inheritance层次结构策略来包含数据库中一个表中的所有数据。

如何通过Fluent NHibernate做到这一点?

我尝试了以下案例:

1。我为父类添加了鉴别器

 public class OneClassMappingOverride : IAutoMappingOverride<OneClass>
 {
        public void Override(AutoMapping<OneClass> mapping)
        {
            mapping.DiscriminateSubClassesOnColumn("Type");
            mapping.SubClass<OneClass>("OneClass");
            mapping.SubClass<TwoClass>("TwoClass");
            mapping.SubClass<ThreeClass>("ThreeClass");
        }
 }

但是我有例外:(XmlDocument)(56,8):XML验证错误:命名空间'urn:nhibernate-mapping-2.2'中的元素'subclass'在命名空间中有无效的子元素'joined-subclass' '瓮:NHibernate的映射-2.2'。预期可能元素列表:'meta,tuplizer,synchronize,property,many-to-one,one-to-one,component,dynamic-component,properties,any,map,set,list,bag,idbag,array,primitive -array,join,subclass,loader,sql-insert,sql-update,sql-delete,resultset,query,sql-query'innamespace'瓮:nhibernate-mapping-2.2'。

因为我为NHibernate提供了以下自动生成的xml映射:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class xmlns="urn:nhibernate-mapping-2.2" name="MyClass.Domain.OneClass, MyClass, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`OneClass`">
    <cache usage="read-write" />
    <id name="PersistenceId" type="System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Id" />
      <generator class="Systematic.Persistence.NHibernate.NHibernateIdGenerator, Systematic.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </id>
    <discriminator type="String">
      <column name="Type" />
    </discriminator>
    <version generated="never" name="PersistedVersion" type="System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" unsaved-value="0">
      <column name="PersistedVersion" />
    </version>
    <property name="OneProp" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="OneProp" length="255" />
    </property>
    <property name="DisplayName" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="DisplayName" length="256" index="idx__DisplayName" />
    </property>
    <property name="SystemName" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="SystemName" length="256" index="idx__SystemName" not-null="true" />
    </property>
    <property name="Version" type="System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Version" not-null="true" />
    </property>
    <property name="Description" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Description" length="10000000" />
    </property>
    <many-to-one class="Systematic.Persistence.PersistenceInfo, Systematic.Api, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" fetch="join" lazy="false" name="Persistence">
      <column name="Persistence_id" index="idx__Persistence" not-null="true" />
    </many-to-one>
    <subclass name="MyClass.Domain.TwoClass, MyClass, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
      <property name="TwoProp" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
        <column name="TwoProp" length="255" />
      </property>
      <joined-subclass name="MyClass.Domain.ThreeClass, MyClass, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
        <key>
          <column name="TwoClass_id" />
        </key>
        <property name="ThreeProp" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
          <column name="ThreeProp" length="255" />
        </property>
      </joined-subclass>
    </subclass>
  </class>
</hibernate-mapping>

2。我试图添加不同的鉴别器

public class OneClassMappingOverride : IAutoMappingOverride<OneClass>
 {
        public void Override(AutoMapping<OneClass> mapping)
        {
            mapping.DiscriminateSubClassesOnColumn("OneType");
        }
 }

 public class TwoClassMappingOverride : IAutoMappingOverride<TwoClass>
 {
        public void Override(AutoMapping<TwoClass> mapping)
        {
            mapping.DiscriminateSubClassesOnColumn("TwoType");
        }
 }

但没有任何系统结果(相同的异常和映射文件)

第3。我试过使用ClassMap&lt;&gt;和SubclassMap&lt;&gt;

public class OneClassMap : ClassMap<OneClass>
{
    public OneClassMap()
    {
        DiscriminateSubClassesOnColumn("Type");

        Id(x => x.Id);

        Map(x => x.OneProp);
    }
}

public class TwoClassMap : SubclassMap<TwoClass>
{
    public TwoClassMap()
    {
        DiscriminatorValue("TwoType");

        Map(x => x.TwoProp);
    }
}

public class ThreeClassMap : SubclassMap<ThreeClass>
{
    public ThreeClassMap()
    {
        DiscriminatorValue("ThreeType");

        Map(x => x.ThreProp);
    }
}

在这种情况下,我有三个表(我的数据库中的OneClass,TwoClass和ThreeClass)我也有以下xml映射文件:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class xmlns="urn:nhibernate-mapping-2.2" name="MyClass.Domain.OneClass, MyClass, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`OneClass`">
    <cache usage="read-write" />
    <id name="PersistenceId" type="System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Id" />
      <generator class="Systematic.Persistence.NHibernate.NHibernateIdGenerator, Systematic.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </id>
    <version generated="never" name="PersistedVersion" type="System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" unsaved-value="0">
      <column name="PersistedVersion" />
    </version>
    <property name="OneProp" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="OneProp" length="255" />
    </property>
    <property name="DisplayName" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="DisplayName" length="256" index="idx__DisplayName" />
    </property>
    <property name="SystemName" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="SystemName" length="256" index="idx__SystemName" not-null="true" />
    </property>
    <property name="Version" type="System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Version" not-null="true" />
    </property>
    <property name="Description" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Description" length="10000000" />
    </property>
    <many-to-one class="Systematic.Persistence.PersistenceInfo, Systematic.Api, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" fetch="join" lazy="false" name="Persistence">
      <column name="Persistence_id" index="idx__Persistence" not-null="true" />
    </many-to-one>
    <joined-subclass name="MyClass.Domain.TwoClass, MyClass, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
      <key>
        <column name="OneClass_id" />
      </key>
      <property name="TwoProp" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
        <column name="TwoProp" length="255" />
      </property>
      <joined-subclass name="MyClass.Domain.ThreeClass, MyClass, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
        <key>
          <column name="TwoClass_id" />
        </key>
        <property name="ThreeProp" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
          <column name="ThreeProp" length="255" />
        </property>
      </joined-subclass>
    </joined-subclass>
  </class>
</hibernate-mapping>

我不知道如何解决我的问题。也许有人帮我解决了这个问题。

非常感谢。

此致 阿列克谢

3 个答案:

答案 0 :(得分:1)

我试图解决类似的问题。同样在我的例子中,我在一个程序集中有一个类,并希望从这个非抽象基础继承不同程序集中的类。流畅的NHibernate将不会映射第二个(继承的)类。正如上面的帖子所描述的那样,似乎只能在

时映射继承层次结构
  1. 只有抽象类位于不同的程序集中
  2. 继承层次结构中的所有非抽象类都在同一个程序集中
  3. 在我看来,这是域建模的一个非常严格的设计限制。接近Fluent NHibernate项目的人是否可以确认不可能从不同程序集中的非抽象类继承?或者有没有人有解决这个问题的解决方案?

    谢谢,罗兰。

答案 1 :(得分:0)

我认为您的案例中的问题可能是由于层次结构中的不同类放在不同的程序集中引起的。我也遇到过这个问题,看起来Fluent不支持这种情况。

我找到了我的情况here,他们通过使父类抽象来修复它。仍在努力寻找是否有其他方式或官方声明它不支持,但尚未成功。

答案 2 :(得分:0)

抱歉,已经晚了。但是迟到总比不到好。

理想情况下,您尝试过的解决方案应该可以正常工作。但是,不幸的是,FNH不支持它。要使其正常工作,您需要实现IAutomappingConfiguration并重写IsDiscriminated方法。像这样:

class MyDefaultConfiguration : DefaultAutomappingConfiguration
{
    private readonly Type[] discriminatedTypes = new[]
    {
        typeof(OneClass), typeof(TwoClass), typeof(ThreeClass)
    };

    public override bool IsDiscriminated(Type type)
    {
        return discriminatedTypes.Contains(type) || base.IsDiscriminated(type);
    }
}

然后,您可以在创建持久模型时使用以下配置:

AutoMap.AssemblyOf<OneClass>(new MyDefaultConfiguration())