1
votes

Using NHibernate : 3.3.2 Fluent NHibernate: 1.3.0 .NET 4.0

Hi all, I'm trying to put together a (very) simple reference project for Fluent NHibernate using automapping, in particular setting up table-per-hierarchy inheritance. I've tried copying the config from an existing (working) project and I've run through the example on the Fluent Wiki page on AutoMapping and inheritance and both give me the same result; the base class that I've set up with table-per-hirearchy gets treated like a regular class.

The domain model looks like so:

namespace Tests
{
    public abstract class Animal
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual int Legs { get; set; }
    }

    public class Cat : Animal {}

    public class Budgie : Animal {}
}

Like I said, simple, just to illustrate inheritance. I'm aware that 'legs' should probably be overridden on the base classes :)

The AutoMapping configuration looks like so:

public class AutoMappingConfig : DefaultAutomappingConfiguration
{
    public override bool ShouldMap(Type type)
    {
        var include = type.IsSubclassOf(typeof(Animal));
        Debug.WriteLineIf(include, string.Format("Included {0} in NHibernate mapping.", type));
        return include;
    }

    public override bool IsDiscriminated(Type type)
    {
        var result = type.In(
            (typeof(Cat)),
            (typeof(Budgie))
            );

        return result;
    }
}

And finally, the configuration/session creation looks like so:

public static ISession NewSession()
{
    var cfg = new AutoMappingConfig();

    var map = AutoMap.AssemblyOf<Animal>(cfg)
        .IgnoreBase<Animal>();

    var dbConfiguration = MsSqlConfiguration.MsSql2008
        .ConnectionString(ConfigurationManager.ConnectionStrings["testdb"].ConnectionString);

    return Fluently.Configure()
        .Mappings(m =>m.AutoMappings.Add(map))
        .Database(dbConfiguration)
        .BuildSessionFactory()
        .OpenSession();
}

Putting that together, I try to create a couple of new records:

[Test]
public void CreateData()
{
    var tiddles = new Cat {Name = "Tiddles", Legs = 4};
    var kylie = new Budgie {Name = "Kylie", Legs = 2};

    using (var transaction = _session.BeginTransaction())
    {
        _session.Save(tiddles); // exception!
        _session.Save(kylie);

        transaction.Commit();
        }
    }
}

The error is:

NHibernate.Exceptions.GenericADOException : could not insert: [Tests.Cat][SQL: INSERT INTO [Cat] (Name, Legs) VALUES (?, ?); select SCOPE_IDENTITY()] ----> System.Data.SqlClient.SqlException : Invalid object name 'Cat'.

A few things to note:

  • The '?' are being filled out if I check with SQL Profiler.
  • When I put a breakpoint in the IsDiscriminated(Type type) method I can see that its being called with the two expected types (Cat & Budgie) and is returning true each time. However, the SQL is writing to the wrong table, and its NOT writing a discriminator column. i.e. even though its been told that these classes are discriminated, they're not being treated as such.
  • In the table, the Id column is an auto-increment identity column.
  • I've tried adding other properties to the two sub classes in case they needed something other than just the base properties to trigger the correct behavior (no difference).

Any help would be greatly appreciated. I'm now convinced its something obvious, but no one here knows much about NHibernate (LightSpeed is another matter) so I've no idea what.


Ok, so the final working code looks like this:

public class AutoMappingConfig : DefaultAutomappingConfiguration
{
    public override bool ShouldMap(Type type)
    {
        var include = type.IsSubclassOf(typeof(Animal)) || type == typeof (Animal);
        Debug.WriteLineIf(include, string.Format("Included {0} in NHibernate mapping.", type));
        return include;
    }

    public override bool IsDiscriminated(Type type)
    {
        return typeof(Animal).IsAssignableFrom(type);
    }
}

public static ISession NewSession()
{
    var cfg = new AutoMappingConfig();

    var map = AutoMap.AssemblyOf<Animal>(cfg)
        .IncludeBase<Animal>();

    var dbConfiguration = MsSqlConfiguration.MsSql2008
        .ConnectionString(ConfigurationManager.ConnectionStrings["testdb"].ConnectionString);

    return Fluently.Configure()
        .Mappings(m =>m.AutoMappings.Add(map))
        .Database(dbConfiguration)
        .BuildSessionFactory()
        .OpenSession();
}

And all is well with the world :)

(i.e. there were three errors)

The instructions here are a bit confusing, as it first talks about using .IgnoreBase<> so NHibernate wont treat the base as entity in its own right, then later mentions using .Includebase<> when using abstract layer supertypes. I'd tried both, but without Firo's answer got no luck.

1

1 Answers

0
votes

you forgot animal

public override bool IsDiscriminated(Type type)
{
    return typeof(Animal).IsAssigneableFrom(type);
}