Quirexx
Quirexx

Reputation: 183

Fluent nHibernate inheritance mappings give errors

So I have mapped almost my whole database succesfully (all the tests of my mappings passed). However, when I tried to implement some inheritance mapping, the tests won't pass.

The normal entities always inherit form the class 'Entity' which contains the Id.

public class Project : Entity<int>
{
    public virtual string Name { get; set; }
    public virtual Client Client { get; set; }
    public virtual Quotation Quotation { get; set; }
    public virtual IList<HoursSpent> HoursSpent { get; set; }

    public Project()
    {
        HoursSpent = new List<HoursSpent>();
    }

    public virtual void AddHoursSpent(HoursSpent HourSpent)
    {
        HourSpent.Project = this;
        HoursSpent.Add(HourSpent);
    }
}

The following situation should be mapped (since I can't post a link to an image):

TABLE [dbo].[project]
[project_id] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](50) NOT NULL,
[client_id] [int] NOT NULL,
[quotation_id] [int] NULL,

PK => project_id
FK => client_id and quotation_id

TABLE [dbo].[quotation](
[quotation_id] [int] IDENTITY(1,1) NOT NULL,
[trainee_cost] [decimal](18, 0) NOT NULL,
[architect_cost] [decimal](18, 0) NOT NULL,

PK => quotation_id

TABLE [dbo].[quotation_per_hour](
[paperwork_expenses] [int] NOT NULL,
[insurance_tax] [decimal](18, 0) NOT NULL,
[hourly_operating_expenses] [decimal](18, 0) NOT NULL,
[quotation_id] [int] NOT NULL,

PK => quotation_id
FK => quotation_id

TABLE [dbo].[quotation_per_percentage](
[quotation_id] [int] NOT NULL,
[wage_percentage] [decimal](18, 0) NOT NULL,

PK => quotation_id
FK => quotation_id

So when I verified the mapping without the subclasses of quotation, the test passed. However when I implement the subclasses I get errors.

First of all the mappings:

public class ProjectMap : ClassMap<Project>
{
    public ProjectMap()
    {
        Table("project");
        Id(x => x.Id)
            .Column("project_id")
            .GeneratedBy.Native();
        Map(x => x.Name)
            .Column("name");
        References(x => x.Client)
            .Column("client_id")
            .Cascade.SaveUpdate();
        References(x => x.Quotation)
            .Column("quotation_id")
            .Cascade.SaveUpdate();
        HasMany(x => x.HoursSpent)
            .Table("hours_spent")
            .KeyColumn("project_id")
            .Cascade.SaveUpdate()
            .Inverse();
    }
}

public class QuotationMap : ClassMap<Quotation>
{
    public QuotationMap()
    {
        Table("quotation");
        Id(x => x.Id)
            .Column("quotation_id")
            .GeneratedBy.Native();
        Map(x => x.TraineeCost)
            .Column("trainee_cost");
        Map(x => x.ArchitectCost)
            .Column("architect_cost");
    }
}

public class QuotationPerHourMap : SubclassMap<QuotationPerHour>
{
    public QuotationPerHourMap()
    {
        Table("quotation_per_hour");
        KeyColumn("quotation_id");
        Map(x => x.PaperworkExpenses)
            .Column("paperwork_expenses");
        Map(x => x.InsuranceTax)
            .Column("insurance_tax");
        Map(x => x.HourlyOperatingExpenses)
            .Column("hourly_operating_expenses");
    }
}

public class QuotationPerPercentageMap : SubclassMap<QuotationPerPercentage>
{
    public QuotationPerPercentageMap()
    {
        Table("quotation_per_percentage");
        KeyColumn("quotation_id");
        Map(x => x.WagePercentage)
            .Column("wage_percentage");
    }
}

So now as my verification I use the following 3 methods, in which every one gives me an error:

[Test]
    public void CanCorrectlyMapProject()
    {
        Project Project = CreateProject();
        var HoursSpent = new List<HoursSpent>()
        {
            CreateHoursSpent(), CreateHoursSpent()
        };

        using (var transaction = session.BeginTransaction())
        {
            new PersistenceSpecification<Project>(session)
                .CheckProperty(c => c.Name, Project.Name)
                .CheckReference(c => c.Client, Project.Client)
                .CheckReference(c => c.Quotation, Project.Quotation)
                .CheckList(c => c.HoursSpent, HoursSpent, (c, p) => c.AddHoursSpent(p))
                .VerifyTheMappings();
        }
    }

    [Test]
    public void CanCorrectlyMapQuotationPerHour()
    {
        QuotationPerHour Quotation = CreateQuotationPerHour();

        using (var transaction = session.BeginTransaction())
        {
            new PersistenceSpecification<QuotationPerHour>(session)
                .CheckProperty(c => c.TraineeCost, Quotation.TraineeCost)
                .CheckProperty(c => c.ArchitectCost, Quotation.ArchitectCost)
                .CheckProperty(c => c.PaperworkExpenses, Quotation.PaperworkExpenses)
                .CheckProperty(c => c.InsuranceTax, Quotation.InsuranceTax)
                .CheckProperty(c => c.HourlyOperatingExpenses, Quotation.HourlyOperatingExpenses)
                .VerifyTheMappings();
        }
    }

    [Test]
    public void CanCorrectlyMapQuotationPerPercentage()
    {
        QuotationPerPercentage Quotation = CreateQuotationPerPercentage();

        using (var transaction = session.BeginTransaction())
        {
            new PersistenceSpecification<QuotationPerPercentage>(session)
                .CheckProperty(c => c.TraineeCost, Quotation.TraineeCost)
                .CheckProperty(c => c.ArchitectCost, Quotation.ArchitectCost)
                .CheckProperty(c => c.WagePercentage, Quotation.WagePercentage)
                .VerifyTheMappings();
        }
    }

The first one gives me:

Lambda_Services_Project.Tests.PersistenceTests.CanCorrectlyMapProject: 
System.ApplicationException : For property 'Quotation' expected type 
Lambda_Services_Project.Entities.QuotationPerPercentage' but got 
Lambda_Services_Project.Entities.Quotation'

I don't get this. Shouldn't I be able to put a subclass of a quotation in the quotation part of the Project object? Because that's why you would implement inheritance.

The second and the third mapping give an error concerning wrong type mapping:

Lambda_Services_Project.Tests.PersistenceTests.CanCorrectlyMapQuotationPerHour:
System.ApplicationException : For property 'InsuranceTax' of type 'System.Single'   
expected '3,6' but got '4'

In my other mappings I don't have a problem to map a float in my object to the decimal in the database. But in the two subclasses I do get a problem because the float properties are apparently added to the database is of System.Single.

I'm starting to believe that the problems lies with the nfluent Nhibernate configuration, and since I don't really understand the configuration part, that's why I posted it here:

private FluentConfiguration GetConfiguration()
    {
        return Fluently.Configure()
            .Database(MsSqlConfiguration.MsSql2008
                .ConnectionString(c => c
                    .Server("")
                    .Database("")
                    .Username(""))
                    .Password(""))
                .ShowSql())
            .Cache(c => c
                .UseQueryCache()
                .ProviderClass<HashtableCacheProvider>())
            .Mappings(m => m
                .FluentMappings
                .AddFromAssemblyOf<Client>())
            .ExposeConfiguration(x => x
                .SetProperty("current_session_context_class", "thread_static"));
    }

I tried changing the mapping to automap and then adding ignorebase or includebase, but this didn't change anything. Is there anyone who could have a clue about what my problem would be?

Upvotes: 1

Views: 223

Answers (1)

Firo
Firo

Reputation: 30813

as seen in the DDL: [insurance_tax] [decimal](18, 0) NOT NULL, the column is mapped without decimal places and is effectivly rounded hence the 3.6 becomes 4. Use .Precision(123) to specify how many decimal places you want to save.

Upvotes: 1

Related Questions