0

I created a generic user repository base class that provides reusable user management functionality.

public class UserRepository<TUser> where TUser : new, IUser
{

}

I have a concrete implementation of IUser called UserImpl, and corresponding mapping class UserImplMap : ClassMap<UserImpl> (they all are in the same namespace and assembly). I add the mapping using AddFromAssemblyOf . I also use this to create / generate the schema.

So far so good and things work as expected.

Now, in a different project, I needed a few additional properties in my IUser implementation class, so I implemented a new class UserImplEx : UserImpl. This class has the additional properties that I needed. Also, I created a new mapping class UserImplExMap : SubclassMap<UserImplEx>

Now when I create schema using this approach, I get two tables one for UserImpl and one for UserImplEx.

Is is possible to configure / code Fluent mapping in some way so that all the properties (self, plus inherited) of UserImplEx get mapped in a single table UserImplEx instead of getting split into two tables?

Alternatively, if I provide full mapping in UserImplExMap : ClassMap<UserImplEx>, then I do get the schema as desired, but I also get an additional table for UserImpl (because corresponding mapping is present in the UserRepository assembly). If I follow this approach, is there a way to tell AddFromAssemblyOf to exclude specific mapping classes?

Firo
  • 30,626
  • 4
  • 55
  • 94
viklele
  • 103
  • 7

1 Answers1

0

Option 1

since you have inhertance here and want the correct type back NH has to store the type somewhere, either through the table the data is in or a discriminator.

If a discriminator column in the table does not matter then add DiscriminatorColumn("userType", "user"); in UserImplMap and DiscriminatorValue("userEx") in UserImplExMap

Option 2

class MyTypeSource : ITypeSource
{
    private ITypeSource _inner = new AssemblyTypeSource(typeof(UserImplMap).Assembly);

    public IEnumerable<Type> GetTypes()
    {
        return _inner.Where(t => t != typeof(UserImplMap)).Concat(new [] { typeof(UserImplExMap) });
    }
    public void LogSource(IDiagnosticLogger logger)
    {
        _inner.LogSource(logger);
    }
    public string GetIdentifier()
    {
        return _inner.GetIdentifier();
    }
}

and when configuring

.Mappings(m =>
{
    var model = new PersistenceModel();
    PersistenceModel.AddMappingsFromSource(new MyTypeSource());
    m.UsePersistenceModel(model);
})
Firo
  • 30,626
  • 4
  • 55
  • 94
  • thanks for the suggesting. Discriminator column will be an unnecessary overhead. As there will not be any other flavor of user in the project, is it not possible to do that without the extra column / table split (which in this case would result in one-to-one mapping)? Or at least exclude / suppress mapping of UserImplMap when I provide full mapping in UserImplExMap? – viklele Jul 19 '13 at 11:35
  • I'll added another option – Firo Jul 22 '13 at 12:15
  • Thanks. I will try that. While going through nHibernate cookbook, I came across an option "table per concrete class". I am looking for something like that. From the book, in nHibernate one can achieve it by using "union-subclass" . I am wondering if there is an equivalent option using Fluent? – viklele Jul 22 '13 at 13:51
  • OK, I think I found a way - haven't tried it yet. There is an option "UseUnionSubclassForInheritanceMapping" suggested in http://stackoverflow.com/questions/845536/programming-to-interfaces-while-mapping-with-fluent-nhibernate – viklele Jul 22 '13 at 13:55
  • this will also create 2 tables. Users and UsersEx which are combined using sql Unions – Firo Jul 22 '13 at 15:09
  • have got tied up in a different project, will try option 2 suggested by you at the earliest opportunity and give feedback. Thanks anyways. – viklele Jul 23 '13 at 13:15