Problems with joinedsubclass

112 views
Skip to first unread message

trul...@googlemail.com

unread,
Aug 25, 2009, 5:26:23 AM8/25/09
to Fluent NHibernate
This was originally a post about JoinedSubClass not working, but i've
since figured out how to get it working however the docs seem
contradictory

in 0.1 i had 3 classes, an abstract base and 2 derived. In the
database there is a table for each entity.

my mapping code for the joinedsubclassness was this:

public class DiaryEntryOverride : IAutoMappingOverride<DiaryEntry>
{
public void Override(AutoMapping<DiaryEntry> mapping)
{
mapping.JoinedSubClass<ActivityDiaryEntry>("id");
mapping.JoinedSubClass<FoodDiaryEntry>("id");
}
}

In 1.0RC however, I couldn't get this configuration to work. Turns out
i needed to make the base class non abstract, set this in the mapping
config and remove the above overrides:

.Setup(s => s.SubclassStrategy = t => SubclassStrategy.JoinedSubclass)

If i make the base class non-abstract, and keep the above override
code, FNH throwns a null reference at:

AutoMapping.cs Line: 174

the docs at http://wiki.fluentnhibernate.org/Auto_mapping#Inheritance
really aren't very helpful :(

"If you want to have your base-class included in NHibernate, then just
don't include the IsBaseType setup we did above! Easy."

I cant see any mention of IsBaseType "above" :( Its mention of
Abstractness is also rather confusing

It might be worth restructuring this part of the wiki to tie in with
the NHibernate nomenclature for mappings/(joined)subclassing as thats
how people are going to be approaching it.

Andrew

James Gregory

unread,
Aug 25, 2009, 5:33:47 AM8/25/09
to fluent-n...@googlegroups.com
Abstract should have no bearing on your mappings. The issue with line 174 is because you're not supplying a lambda to the JoinedSubClass method (and we're not checking for nulls), pass it an empty lambda and it should work.

mapping.JoinedSubClass<ActiveDiaryEntry>("id", m => {});

As for the docs, IsBaseType was replaced in favor of IgnoreBase, I hadn't updated that part of the content to reflect that. If you want your whole class hierarchy mapped as subclasses then you really don't need to do anything, that's what that section is saying.

Why is the abstract section confusing? There is no implications for using abstract base classes, they work fine.

trul...@googlemail.com

unread,
Aug 25, 2009, 6:05:55 AM8/25/09
to Fluent NHibernate
:((((

please clarify this for me, im aware that im probably doing something
wrong, but following the docs doesnt seem to work, neither does trial
and error :(

with or without this:

.Setup(s => s.SubclassStrategy = t => SubclassStrategy.JoinedSubclass)

if my base is abstract (which i want), i get xml mappings for each of
my subclasses will the properties from the base table on it. this is
wrong and obviously doesnt work with my db

If i make my base class non-abstract, i get a single baseclass.xml,
with the joined mappings in it (which is correct)

however, the <key><column name="DiaryEntry_Id" is wrong (should be
"id" from the base class), adding/removing the below makes no
difference:

public class DiaryEntryOverride : IAutoMappingOverride<DiaryEntry>
{
public void Override(AutoMapping<DiaryEntry> mapping)
{
mapping.JoinedSubClass<ActivityDiaryEntry>("id", m => { });
mapping.JoinedSubClass<FoodDiaryEntry>("id", m => { });
}
}

Making an override for one of the derived classes (to use ignore
property as per your recommendation yesterday) the ignoreproperty
doesnt work, the property still gets mapped.

public class ActivityDiaryEntryOverride :
IAutoMappingOverride<ActivityDiaryEntry>
{
public void Override(AutoMapping<ActivityDiaryEntry> mapping)
{
// this doesnt help, its ignored
mapping.Id(m => m.Id, "Id");

mapping.References(ade => ade._activity, "Activity_Id");

// This doesnt work
mapping.IgnoreProperty(x => x.Activity);
}
}

Am i being a noob?

Thanks

Andrew


On Aug 25, 10:33 am, James Gregory <jagregory....@gmail.com> wrote:
> Abstract should have no bearing on your mappings. The issue with line 174 is
> because you're not supplying a lambda to the JoinedSubClass method (and
> we're not checking for nulls), pass it an empty lambda and it should work.
> mapping.JoinedSubClass<ActiveDiaryEntry>("id", m => {});
>
> As for the docs, IsBaseType was replaced in favor of IgnoreBase, I hadn't
> updated that part of the content to reflect that. If you want your whole
> class hierarchy mapped as subclasses then you really don't need to do
> anything, that's what that section is saying.
>
> Why is the abstract section confusing? There is no implications for using
> abstract base classes, they work fine.
>
> On Tue, Aug 25, 2009 at 10:26 AM, trull...@googlemail.com <
>
>
>
> trull...@googlemail.com> wrote:
>
> > This was originally a post about JoinedSubClass not working, but i've
> > since figured out how to get it working however the docs seem
> > contradictory
>
> > in 0.1 i had 3 classes, an abstract base and 2 derived. In the
> > database there is a table for each entity.
>
> > my mapping code for the joinedsubclassness was this:
>
> > public class DiaryEntryOverride : IAutoMappingOverride<DiaryEntry>
> > {
> >        public void Override(AutoMapping<DiaryEntry> mapping)
> >        {
> >                mapping.JoinedSubClass<ActivityDiaryEntry>("id");
> >                mapping.JoinedSubClass<FoodDiaryEntry>("id");
> >        }
> > }
>
> > In 1.0RC however, I couldn't get this configuration to work. Turns out
> > i needed to make the base class non abstract, set this in the mapping
> > config and remove the above overrides:
>
> > .Setup(s => s.SubclassStrategy = t => SubclassStrategy.JoinedSubclass)
>
> > If i make the base class non-abstract, and keep the above override
> > code, FNH throwns a null reference at:
>
> > AutoMapping.cs    Line: 174
>
> > the docs athttp://wiki.fluentnhibernate.org/Auto_mapping#Inheritance

James Gregory

unread,
Aug 25, 2009, 6:13:16 AM8/25/09
to fluent-n...@googlegroups.com
Oh I see what you're doing. Abstract base classes are considered to be layer supertypes, which is why you're getting individual mappings for the subclasses.

This is tricky, because most users don't want their abstract classes including in their hierarchies, as they're generally layer supertypes. By turning off this behavior we'd require all users to explicitly ignore their abstract base types, which sucks; however, not doing that means we have to cater for your scenario. Any suggestions on how you'd instruct FNH to not ignore your type?

As for the ignore, that might be a bug.

trul...@googlemail.com

unread,
Aug 25, 2009, 6:26:07 AM8/25/09
to Fluent NHibernate
I don't pretend to be any kind of NH expert, just been following the
InAction book and tuts online. Perhaps I'm not solving my problem in
the right way (choice of schema etc), but i thought so. NH In action
says what im doing its perfectly fine, heres a quote:

"Every subclass that declares persistent properties - including
abstract classes and even interfaces - has its own table. Unlike the
strategy that uses a table per concrete class, the table here contains
columns only for each non-inherited property along with a primary key
that is also a foreign key for the base class table"

Am i misunderstanding this?

Either way, this worked in 0.1 (the 0.1 docs agreed with InAction +
Ayende) and now doesn't in 1.0.

Not sure what to suggest, as...im not sure i understand your argument,
please explain.

Even so, how come i cant change the key column name, is this also a
bug?

Andrew



On Aug 25, 11:13 am, James Gregory <jagregory....@gmail.com> wrote:
> Oh I see what you're doing. Abstract base classes are considered to be layer
> supertypes, which is why you're getting individual mappings for the
> subclasses.
> This is tricky, because most users don't want their abstract classes
> including in their hierarchies, as they're generally layer supertypes. By
> turning off this behavior we'd require all users to explicitly ignore their
> abstract base types, which sucks; however, not doing that means we have to
> cater for your scenario. Any suggestions on how you'd instruct FNH to not
> ignore your type?
>
> As for the ignore, that might be a bug.
>
> On Tue, Aug 25, 2009 at 11:05 AM, trull...@googlemail.com <

trul...@googlemail.com

unread,
Aug 25, 2009, 6:30:03 AM8/25/09
to Fluent NHibernate
Hmmm, just a quicky as i investigate, this functionality *seems* to
work with fluent mappings, its just the automapper that doesnt behave

Andrew

On Aug 25, 11:26 am, "trull...@googlemail.com"

James Gregory

unread,
Aug 25, 2009, 6:36:10 AM8/25/09
to fluent-n...@googlegroups.com
The automapper is built on a series of presumptions about your domain, these are based on the most common scenarios for how a domain is structured. The most common scenario involving abstract classes is that they're a layer supertype, this means that if the automapper encounters one it will ignore it for mapping purposes because generally you don't want to map it as an entity.

NH in Action, fluent mappings, and hbm mappings all differ from the automappings because you explicitly state which classes you want to be entities. That's why it works with fluent mappings, because by creating a ClassMap of your abstract class you're telling FNH that you want it to be an entity.

The automapper is behaving exactly as it should, we just need to think of a way to allow your particular design. I have no intention of being compatible with 0.1, just as long as there is a way to do what you want to.

The key and ignoring properties I will investigate.

trul...@googlemail.com

unread,
Aug 25, 2009, 7:16:25 AM8/25/09
to Fluent NHibernate
Thats cool, i wasnt saying "it should work like 0.1" just that 0.1
works by default, i understand what you mean though, your new default
is probably the most common.

I don't mind how i tell FNH to work the way I want, as long as I
can :)

As well as the key and ignoreproperty, the table name seems to be
missing too?

Also, (may have already asked this, sorry) should i *need* to do this:

AutoMap.Where(t => !t.Name.EndsWith("DiaryEntry"))

to tell the AutoMapper to ignore my explicit subclass mappings:

mappingConfiguration.FluentMappings
.Add<DiaryEntryMapping>()
.Add<FoodDiaryEntryMapping>()
.Add<ActivityDiaryEntryMapping>();

I seem to remember you saying it should ignore classes already
fluently mapped

Thanks for your quick feedback :)

Regards

Andrew



On Aug 25, 11:36 am, James Gregory <jagregory....@gmail.com> wrote:
> The automapper is built on a series of presumptions about your domain, these
> are based on the most common scenarios for how a domain is structured. The
> most common scenario involving abstract classes is that they're a layer
> supertype <http://martinfowler.com/eaaCatalog/layerSupertype.html>, this
> means that if the automapper encounters one it will ignore it for mapping
> purposes because generally you don't want to map it as an entity.
>
> NH in Action, fluent mappings, and hbm mappings all differ from the
> automappings because you *explicitly state* which classes you want to be
> entities. That's why it works with fluent mappings, because by creating a
> ClassMap of your abstract class you're telling FNH that you want it to be an
> entity.
>
> The automapper is behaving exactly as it should, we just need to think of a
> way to allow your particular design. I have no intention of being compatible
> with 0.1, just as long as there is a way to do what you want to.
>
> The key and ignoring properties I will investigate.
>
> On Tue, Aug 25, 2009 at 11:30 AM, trull...@googlemail.com <

James Gregory

unread,
Aug 25, 2009, 9:45:17 AM8/25/09
to fluent-n...@googlegroups.com
I've just committed a change that should allow you to use your abstract class.

Change your AutoMap to use IncludeBase<DiaryEntry>(), that'll force the automapper to use your class even though it's abstract.

I'll update the wiki once you've verified that change works.

As for your other bugs, are they still a problem with the latest binary?

James Gregory

unread,
Aug 28, 2009, 6:00:03 PM8/28/09
to fluent-n...@googlegroups.com
Well, hopefully this is fixed because 1.0 is going out tonight. I've investigated as much as I can without you, but I haven't been able to find any issues.

IgnoreProperty works from within a joined-subclass. Abstract classes can now be forced with IncludeBase. The key is overrideble by convention, but not in the override directly unfortunately.

If it still doesn't work it's either you, or you'll have to wait until 1.1.
Reply all
Reply to author
Forward
0 new messages