开发者

Fluent NHibernate - mixing table-per-subclass and table-per-class-hierarchy

Give the following structure,

MyBaseClass {
  public int Id {get; private set;}
}

MySubclassWithDiscriminator : MyBaseClass {
}

MySubclass : MyBaseClass {
  public string SomeThing {get; set;}
}

How would I use Fluent NH to map these correctly, using a combination of table-per-subclass and table-per-class-hierarchy? I've tried a custom AutomappingConfiguration, but seem to be going around in circles:

public class AutomappingConfiguration : DefaultAutomappingConfiguration
{
    public override bool ShouldMap(Type type)
    {
        return type.Namespace.Contains("Entities");
    }

    public override bool IsDiscriminated(Type type)
    {
        // only classes with additional properties should be 
        // using the table-per-subclass strategy
        if ((type.IsAssignableFrom(typeof(MyBaseClass)) || 
             type.IsSubclassOf(typeof(MyBaseClass)) && 
             type.GetProperties(BindingFlags.Public | 
                                BindingFlags.FlattenHierarchy)
             .Count() <= 1))
        {
            return true;
        }
        return false;
    }
}

public class SubclassConvention : ISubclassConvention
{
    public void Apply(ISubclassInstance instance)
    {
        // Use the short name of the type, not the full name
        instance.DiscriminatorValue(instance.Entity开发者_如何转开发Type.Name);
    }
}

It seems to me from my investigation that the use of the Discriminator is a binary choice when using FNH, while an HBM has the ability to have a Discriminator column and a subclass at the same time.


EDIT - 2011-05-12

I rewrote this post to try to address James Gregory's comments.

Here's the HBM that I'm trying to achieve:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class 
   xmlns="urn:nhibernate-mapping-2.2" 
   name="Mixed_Parent" 
   abstract="true" 
   table="`Mixed_Parent`">
    <id name="Id" type="System.Int32">
      <generator class="identity" />
    </id>
    <discriminator type="String">
      <column name="discriminator" />
    </discriminator>
    <subclass 
     name="Mixed_TPCH_Child" 
     discriminator-value="Mixed_TPCH_Child" />
    <subclass 
     name="Mixed_TPS_Child" 
     discriminator-value="Mixed_TPS_Child">
      <join table="`Mixed_TPS_Child`" >
        <key column="Id" />
        <property name="Description" type="String">
          <column name="Description" />
        </property>
      </join>
    </subclass>
  </class>
</hibernate-mapping>

So, what I've seen is that the HBM that's generated is EITHER a <joined-subclass> or <subclass> without the <join> sub-element, never a combination of the two. Am I missing something here?

Here's a failing test that can be added to the SubclassPersistenceModelTests to illustrate:

namespace MixedTablePerSubclassWithTablePerClassHierarchy
{
    public class Mixed_Parent
    {
        public virtual int Id { get; set; }
    }

    public class Mixed_TPCH_Child
    {

    }

    public class Mixed_TPS_Child
    {
        public virtual string Description { get; set; }
    }

    public class Mixed_ParentMap : ClassMap<Mixed_Parent>
    {
        public Mixed_ParentMap()
        {
            Id(x => x.Id);
            DiscriminateSubClassesOnColumn("discriminator");
        }
    }

    public class Mixed_TPCH_ChildMap : SubclassMap<Mixed_TPCH_Child>
    { }

    public class Mixed_TPS_ChildMap : SubclassMap<Mixed_TPS_Child>
    {
        public Mixed_TPS_ChildMap()
        {
            Map(x => x.Description);
        }
    }
}

[Test]
public void ShouldAllowMixedTablePerSubclassWithTablePerClassHierarchy()
{
    var model = new PersistenceModel();

    model.Add(
        new MixedTablePerSubclassWithTablePerClassHierarchy
            .Mixed_ParentMap());
    model.Add(
        new MixedTablePerSubclassWithTablePerClassHierarchy
            .Mixed_TPCH_ChildMap()
    );
    model.Add(
        new MixedTablePerSubclassWithTablePerClassHierarchy
            .Mixed_TPS_ChildMap());

    var classMapping = model.BuildMappings()
        .First()
        .Classes.First();

    // WHAT SHOULD THIS NUMBER BE (0, 1 or 2)?
    classMapping.Subclasses.Count().ShouldEqual(1);
    classMapping
        .Subclasses
        .First()
        .Type
        .ShouldEqual(
            typeof(
                MixedTablePerSubclassWithTablePerClassHierarchy
                .Mixed_TPS_Child)
        ); // WHICH OF THE CHILDREN WOULD BE FIRST?
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜