How do I get table-per-inheritance-hierarchy to work with Fluent NHibernate AutoMapping and integer discriminators?

StackOverflow https://stackoverflow.com/questions/19729860

Question

I've tried searching for information on this all over the place, but no one seems to quite cover this issue. I've reduced it to the following example.

This is my database :

create table ThingTypes
(
    Id int,
    Name varchar(50) not null

    constraint PK_ThingTypes primary key (Id)
)
go

insert into ThingTypes(Id, Name) Values(1, 'ThingTypeOne')
insert into ThingTypes(Id, Name) Values(2, 'ThingTypeTwo')

create table Things
(
    Id int identity,
    Name varchar(50) not null,
    ThingTypeId int not null

    constraint PK_Things primary key (Id),
    constraint FK_Things_ThingTypes foreign key (ThingTypeId) references ThingTypes(Id)
)
go

This is my model :

public abstract class Thing
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
}
public class ThingTypeOne : Thing { }
public class ThingTypeTwo : Thing { }

These are my mappings :

public class ThingOverride : IAutoMappingOverride<Thing>
{
    public void Override(AutoMapping<Thing> mapping)
    {
        mapping.DiscriminateSubClassesOnColumn("ThingTypeId", 0);
    }
}

public class ThingTypeOneMap : SubclassMap<ThingTypeOne>
{
    public ThingTypeOneMap()
    {
        DiscriminatorValue(1);
    }
}

public class ThingTypeTwoMap : SubclassMap<ThingTypeTwo>
{
    public ThingTypeTwoMap()
    {
        DiscriminatorValue(2);
    }
}

This is my ISessionFactory builder :

public static ISessionFactory GetFactory(string connectionString)
{
    var configuration = new Configuration().AddProperties(new Dictionary<string, string>
        {
            {Environment.ConnectionDriver, typeof (SqlClientDriver).FullName},
            {Environment.Dialect, typeof (MsSql2008Dialect).FullName},
            {Environment.ConnectionProvider, typeof (DriverConnectionProvider).FullName},
            {Environment.ConnectionString, connectionString},
            {Environment.ShowSql, "true"},
            {Environment.BatchSize, "100"},
            {Environment.Isolation, "ReadCommitted"}
        });

    return Fluently.Configure(configuration)
                    .Mappings(m =>
                        {
                            m.FluentMappings.AddFromAssemblyOf<ThingTypeOneMap>();
                            m.AutoMappings.Add(AutoMap.AssemblyOf<Thing>(new DefaultAutomappingConfiguration())
                                                        .UseOverridesFromAssemblyOf<ThingOverride>()
                                );
                        })
                    .BuildSessionFactory();
}

And this is my failing test :

var sessionFactory = SessionFactoryBuilder.GetFactory(@"Data Source=localhost;Initial Catalog=ThingDatabase;Trusted_Connection=True;");
using (var session = sessionFactory.OpenSession())
{
    session.BeginTransaction();
    session.SaveOrUpdate(new ThingTypeOne
        {
            Name = "New Thing Type One"
        });
    session.Transaction.Commit();
}

It fails because it tries to insert into table "ThingTypeOne", which obviously doesn't exist. What do I need to do to get Fluent NHibernate to actually pay attention to the DiscriminateSubClassesOnColumn property that I've set?

Was it helpful?

Solution

instead of subclassmaps for each subclass add a convention

class DiscriminatorValueConvention : ISubclassConvention
{
    public void Apply(ISubclassInstance instance)
    {
        if (instance.Type == typeof(ThingTypeOne))
        {
            instance.DiscriminatorValue(1);
        }
        else if (instance.Type == typeof(ThingTypeTwo))
        {
            instance.DiscriminatorValue(2);
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top