Problems with generated SQL #167

Open
lakario opened this Issue Sep 17, 2012 · 3 comments

Comments

Projects
None yet
2 participants
@lakario

lakario commented Sep 17, 2012

I'm having a bit of trouble with some SQL generated by my FluentNHibernate mappings. I'm not doing anything too complex, but unfortunately it's not behaving the way I would have expected.

I have a table-per-type hierarchy relating a ContentModule table to several sub-type tables. For the CategoryContentModule and EventContentModule types, there is an additional one-to-many relationship to the ContentItem table.

Mapping

Here's the class definition for my tables; make note of the intermediary abstract type ContentItemContentModule:

public abstract class ContentModule
{
    public virtual string Name { get; set; }
    public virtual ModuleStatus Status { get; set; }
    public virtual DateTime? ExpirationDateTime { get; set; }
    public virtual DateTime? LastPublishedDateTime { get; set; }
    public virtual DateTime? LastUnpublishedDateTime { get; set; }
}

public class CustomContentModule : ContentModule
{
    public virtual string ViewPath { get; set; }
}

public abstract class ContentItemContentModule : ContentModule
{
    public virtual ContentItem ContentItem { get; set; }
}

public class EventContentModule : ContentItemContentModule
{
    public virtual Event Event { get; set; }
}

public class CategoryContentModule : ContentItemContentModule
{
    public virtual Category Category { get; set; }
}

Finally, my mappings:

public class ContentModuleMapping : ClassMap<ContentModule>
{
    public ContentModuleMapping()
    {
        Map(x => x.Name);
        Map(x => x.Status).CustomType<ContentModule.ModuleStatus>();
        Map(x => x.ExpirationDateTime);
        Map(x => x.LastPublishedDateTime);
        Map(x => x.LastUnpublishedDateTime);
    }
}

public class CustomContentModuleMapping : SubclassMap<CustomContentModule>
{
    public CustomContentModuleMapping()
    {
        Map(x => x.ViewPath).Not.Nullable();
    }
}

public class EventContentModuleMapping : SubclassMap<EventContentModule>
{
    public EventContentModuleMapping()
    {
        References(x => x.ContentItem).Nullable().Cascade.None();
        References(x => x.Event).Not.Nullable().LazyLoad().Cascade.None();
    }
}

public class CategoryContentModuleMapping : SubclassMap<CategoryContentModule>
{
    public CategoryContentModuleMapping()
    {
        References(x => x.ContentItem).Nullable().Cascade.None();
        References(x => x.Category).Not.Nullable().LazyLoad().Cascade.None();
    }
}

As you can see, the intermediary type ContentItemContentModule is never mapped and exists only to provide the ContentItem property of its sub-types. In the mappings for each sub-type I explicitly map the ContentItem property.


When this mapping is registered and I attempt to retrieve a collection of ContentModule items via NHibernate, the generated SQL produces a non-existent column called ContentItemContentModuleId.

I've attempted explicitly setting the column name of the ContentItem reference to 'ContentItemId' (matching the table structure), but this did not work. After some experimentation I determined that referencing the ContentItem property was not the problem, but rather having the intermediary class ContentItemContentModule was. If I remove the intermediary abstract class and move the ContentItem property into each sub-type, the SQL is generated correctly and everything works.

The solution I came up with was simply to eliminate the intermediary abstract type and instead use an interface to achieve the same result in my code, but this is obviously a workaround.


TL;DR For some reason, FluentNHibernate is having problems with there being an unmapped abstract type between a mapped base abstract type and a mapped concrete type in a table-per-type hierarchy.

@chester89

This comment has been minimized.

Show comment Hide comment
@chester89

chester89 Sep 17, 2012

Collaborator

I'm not an expert in mapping inheritance hierarchies, but if you use table-per-type, shouldn't all types in hierarchy be mapped, including abstract ones? Although I'm not sure what's Fluent default behaviour in this particular case

Collaborator

chester89 commented Sep 17, 2012

I'm not an expert in mapping inheritance hierarchies, but if you use table-per-type, shouldn't all types in hierarchy be mapped, including abstract ones? Although I'm not sure what's Fluent default behaviour in this particular case

@lakario

This comment has been minimized.

Show comment Hide comment
@lakario

lakario Sep 18, 2012

@chester89 While I do not disagree, the intermediary type is not intended to have its own table and if I map it, FluentNHibernate will assume that it does.

lakario commented Sep 18, 2012

@chester89 While I do not disagree, the intermediary type is not intended to have its own table and if I map it, FluentNHibernate will assume that it does.

@chester89

This comment has been minimized.

Show comment Hide comment
@chester89

chester89 Feb 19, 2013

Collaborator

can you post generated hbm files for this? It just got to me that errors in SQL may have to do with NHibernate

Collaborator

chester89 commented Feb 19, 2013

can you post generated hbm files for this? It just got to me that errors in SQL may have to do with NHibernate

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment