开发者

how to achieve table per concrete class when base class is abstract in fluent nhibernate?

开发者 https://www.devze.com 2023-04-04 00:32 出处:网络
i have the following scenario public abstract class BaseClass { public virtual int Id {get; set}; public virtual string Name {get; set;}

i have the following scenario

public abstract class BaseClass
{
  public virtual int Id {get; set};
  public virtual string Name {get; set;}
}

public class FirstSubClass : BaseClass
{
   //properties and behaviour here
}

public class SecondSubClass : BaseClass
{
  //properties of SecondSubclass Here
}

public class ProcessStep
{
   public virtual IList<BaseClass> ContentElements {get; set;}  
}

for mapping i have used following code snippet :-

this._sessionFactory =
                          Fluently.Configure().Database(SQLiteConfiguration.Standard
                          .ConnectionString(@"Data Source=SqliteTestSqlDataAccess.s3db;    Version=3; New=True; Pooling=True; Max Pool Size=1;"))
                          .Mappings(m => m.AutoMappings.Add(AutoMap.Assembly(assemblyWithDomainClasses).Conventions.Add(DefaultCascade.All())))
                          .ExposeConfiguration(BuildSchema)
                          .BuildSessionFactory();

By default fluent will ignore the abstract base class that is BaseClass. But as in the class ProcessStep there is property ContentElements which returns IList , i am getting an exception:- NHibernate.MappingException : Association references u开发者_如何学编程nmapped class: BaseClass

If i include the base class using the IncludeBase(typeof(BaseClass)) then it works fine but it creates a table for BaseClass and Derived classes and the records are linked with FK-PK relationship(table per subclass). What i want to achieve is table per concrete class. that is each derive class will have it's own table where there will all properties of derived class + properties in the base class. Any idea how to achieve it?


Since I haven't seen your mapping, let me provide mine. You could achieve this by doing like this

public class BaseClassMap:ClassMap<BaseClass>
{
    public BaseClassMap()
    {
        /*
         * Identity generator can't be native because subclass objects should be unique
         * So use HiLo or Guid or other generators which will generate unique id on the child tables
         */
        Id(x => x.Id).GeneratedBy.Guid(); 
        Map(x => x.Name);
        UseUnionSubclassForInheritanceMapping(); // This is important - uses union-subclass mappings for the derived classes
    }
}

public class FirstSubClassMap : SubclassMap<FirstSubClass>
{
    public FirstSubClassMap()
    {
        Table("FirstSubClassTable");
        // Map properties for FirstSubClass
    }
}

public class SecondSubClassMap : SubclassMap<SecondSubClass>
{
    public SecondSubClassMap()
    {
        Table("SecondSubClassTable");
        // Map properties for SecondSubClass
    }
}


It caused me headache to implement the "Table per Concrete Class" inheritance strategy with an abstract base class with nhibernate automapping. But I think, I've finally found a solution and want to share it with you. I also think, it's not added to the automapping docs, because it's maybe considered as a "weak" database design.

First here are some resources I found about this topic:

  • https://www.codeproject.com/Articles/232034/Inheritance-mapping-strategies-in-Fluent-Nhibernat Example implementation of inheritance strategies in fluent nhibernate (!automapping).
  • https://github.com/jagregory/fluent-nhibernate/wiki/Automapping-inheritance Documentation of inheritance strategies in fluent nhibernate with automapping.
  • (can't add another link) https : // github . com /jagregory/fluent-nhibernate/pull/25/commits/2984c8c4e89aa4cec8625538f763c5931121a4e7 Bug-Fix Union-SubClass implementation (Table per Concrete Class)

These resources basically describe how you need to do it:

  1. As you already mentioned fluent nhibernate ignores abstract base classes. So you need to add them explicitly.
// abstractBaseTypes is just a simple enumeration of base types
// model is the AutoPersistenceModel
abstractBaseTypes.ForEach(m => model = model.IncludeBase(m));
  1. a) If you know the abstract base types at compile time you can use
//sets the union subclass strategy for the known base model
model.Override<SuperType>(m => m.UseUnionSubclassForInheritanceMapping()))
  1. b) If you don't know the concrete types you can create a mapping override for each base type:
public class AbstractRightEntryMappingOverride : IAutoMappingOverride<AbstractRightEntry>
{
    public void Override(AutoMapping<AbstractRightEntry> mapping)
    {
        mapping.UseUnionSubclassForInheritanceMapping();
    }
}

// You need to tell nhibernate where to find the overriden mappings. 
// You simply can add the assemblies again.
modelAssemblies.ForEach(a => model = model.UseOverridesFromAssembly(a));
0

精彩评论

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