Inheritance Mapping with Fluent NHibernate

后端 未结 4 2122
既然无缘
既然无缘 2020-12-04 18:15

Given the following scenario, I want map the type hierarchy to the database schema using Fluent NHibernate.

I am using NHibernate 2.0


Type Hier

相关标签:
4条回答
  • 2020-12-04 18:51

    Well, I'm not sure that it's quite right, but it might work... If anyone can do this more cleanly, I'd love to see it (seriously, I would; this is an interesting problem).

    Using the exact class definitions you gave, here are the mappings:

    public class ItemMap : ClassMap<Item>
    {
        public ItemMap()
        {
            Id(x => x.ItemId);
            Map(x => x.ItemType);
            Map(x => x.FieldA);
    
            AddPart(new ConcreteItemYMap());
        }
    }
    
    public class SubItemMap : ClassMap<SubItem>
    {
        public SubItemMap()
        {
            WithTable("Item");
    
            // Get the base map and "inherit" the mapping parts
            ItemMap baseMap = new ItemMap();
            foreach (IMappingPart part in baseMap.Parts)
            {
                // Skip any sub class parts... yes this is ugly
                // Side note to anyone reading this that might know:
                // Can you use GetType().IsSubClassOf($GenericClass$)
                // without actually specifying the generic argument such
                // that it will return true for all subclasses, regardless
                // of the generic type?
                if (part.GetType().BaseType.Name == "JoinedSubClassPart`1")
                    continue;
                AddPart(part);
            }
            Map(x => x.FieldB);
            AddPart(new ConcreteItemXMap());
        }
    }
    
    public class ConcreteItemXMap : JoinedSubClassPart<ConcreteItemX>
    {
        public ConcreteItemXMap()
            : base("ItemId")
        {
            WithTableName("ConcreteItemX");
            Map(x => x.FieldC);
        }
    }
    
    public class ConcreteItemYMap : JoinedSubClassPart<ConcreteItemY>
    {
        public ConcreteItemYMap()
            : base("ItemId")
        {
            WithTableName("ConcreteItemY");
            Map(x => x.FieldD);
        }
    }
    

    Those mappings produce two hbm.xml files like so (some extraneous data removed for clarity):

      <class name="Item" table="`Item`">
        <id name="ItemId" column="ItemId" type="Int32">
          <generator class="identity" />
        </id>
        <property name="FieldA" type="String">
          <column name="FieldA" />
        </property>
        <property name="ItemType" type="String">
          <column name="ItemType" />
        </property>
        <joined-subclass name="ConcreteItemY" table="ConcreteItemY">
          <key column="ItemId" />
          <property name="FieldD">
            <column name="FieldD" />
          </property>
        </joined-subclass>
      </class>
    
      <class name="SubItem" table="Item">
        <id name="ItemId" column="ItemId" type="Int32">
          <generator class="identity" />
        </id>
        <property name="FieldB" type="String">
          <column name="FieldB" />
        </property>
        <property name="ItemType" type="String">
          <column name="ItemType" />
        </property>
        <property name="FieldA" type="String">
          <column name="FieldA" />
        </property>
        <joined-subclass name="ConcreteItemX" table="ConcreteItemX">
          <key column="ItemId" />
          <property name="FieldC">
            <column name="FieldC" />
          </property>
        </joined-subclass>
      </class>
    

    It's ugly, but it looks like it might generate a usable mapping file and it's Fluent! :/ You might be able to tweak the idea some more to get exactly what you want.

    0 讨论(0)
  • 2020-12-04 18:53

    This is how I resolved my inheritance problem:

    public static class DataObjectBaseExtension
    {
        public static void DefaultMap<T>(this ClassMap<T> DDL) where T : IUserAuditable 
        {
            DDL.Map(p => p.AddedUser).Column("AddedUser");
            DDL.Map(p => p.UpdatedUser).Column("UpdatedUser");
        }
    }
    

    You can then add this to your superclass map constructor:

    internal class PatientMap : ClassMap<Patient>
    {
        public PatientMap()
        {
            Id(p => p.GUID).Column("GUID");
            Map(p => p.LocalIdentifier).Not.Nullable();
            Map(p => p.DateOfBirth).Not.Nullable();
            References(p => p.Sex).Column("RVSexGUID");
            References(p => p.Ethnicity).Column("RVEthnicityGUID");
    
            this.DefaultMap();
        }
    
    
    }
    
    0 讨论(0)
  • 2020-12-04 19:02

    I know this is really old, but it is now pretty simple to set up fluent to generate the exact mapping you initially desired. Since I came across this post when searching for the answer, I thought I'd post it.

    You just create your ClassMap for the base class without any reference to your subclasses:

    public class ItemMap : ClassMap<Item>
    {
        public ItemMap()
        {
            this.Table("Item");
            this.DiscriminateSubClassesOnColumn("ItemType");
            this.Id(x => x.ItemId, "ItemId");
            this.Map(x => x.FieldA, "FieldA");
        }
    }
    

    Then map your abstract subclass like this:

    public class SubItemMap: SubclassMap<SubItemMap>
    {
        public SubItemMap()
        {
            this.Map(x => x.FieldB);
        }
    }
    

    Then map your concrete subclasses like so:

    public class ConcreteItemXMap : SubclassMap<ConcreteItemX>
    {
        public ConcretItemXMap()
        {
            this.Join("ConcreteItemX", x =>
            {
                x.KeyColumn("ItemID");
                x.Map("FieldC")
            });
        }
    }
    

    Hopefully this helps somebody else looking for this type of mapping with fluent.

    0 讨论(0)
  • 2020-12-04 19:10

    The line of code: if (part.GetType().BaseType.Name == "JoinedSubClassPart1") can be rewritten as follows:

    part.GetType().BaseType.IsGenericType && part.GetType().BaseType.GetGenericTypeDefinition() == typeof(JoinedSubClassPart<>)
    
    0 讨论(0)
提交回复
热议问题