1
votes

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?

1
the first error goes away when specifying References(x => x.Quotation).Not.LazyLoad()? - Firo

1 Answers

1
votes

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.