I’ve just committed a breaking change to Fluent NHibernate (as of r184), which I thought I’d document here for anyone interested; it’s a reworking of the subclass syntax.
Mapping multiple subclasses with the same parent wasn’t a very fluent affair, and it was pretty wordy too. You can see a comparison of the old and new syntaxes below.
Before
var discriminator = DiscriminateSubClassesOnColumn<string>("Type");
discriminator.SubClass<B>()
.IdentifiedBy("bID")
.MapSubClassColumns(m =>
{
m.Map(x => x.BProperty);
});
discriminator.SubClass<C>()
.IdentifiedBy("cID")
.MapSubClassColumns(m =>
{
m.Map(x => x.CProperty);
});
After
DiscriminateSubClassesOnColumn("Type")
.SubClass<B>(m =>
{
m.Map(x => x.BProperty);
})
.SubClass<C>(m =>
{
m.Map(x => x.CProperty);
});
Much nicer! The changes you can see here are:
DiscriminateSubClassesOnColumnnow assumes your discriminator is astringif you don’t specify a typeSubClassdefaults to using the subclass type name as a discriminator valueIdentifiedByandMapSubClassColumnsare now merged intoSubClassas overloads.
Nested subclasses were never really supported in Fluent NHibernate, but they were hackable. You could abuse DiscriminateSubClassesOnColumn to let you trick it into creating nested classes. This worked but it led to some really ugly mapping code (and a nasty hack in the Fluent NHibernate codebase). I’ve given some loving to this area and have managed to really sweeten-up the syntax.
Before
DiscriminateSubClassesOnColumn<string>("Type")
.SubClass<B>()
.IdentifiedBy("bID")
.MapSubClassColumns(m =>
{
m.Map(x => x.BProperty);
m.DiscriminateSubClassesOnColumn<string>("Type")
.SubClass<C>()
.IdentifiedBy("cID")
.MapSubClassColumns(m =>
{
m.Map(x => x.CProperty);
});
});
After
DiscriminateSubClassesOnColumn("Type")
.SubClass<B>(m =>
{
m.Map(x => x.BProperty);
m.SubClass<C>(m =>
{
m.Map(x => x.CProperty);
});
});
The changes in this one are:
SubClasscan now be used within subclasses without having to reuseDiscriminateSubClassesOnColumn
All in all, these changes serve to make mapping subclasses in Fluent NHibernate a little bit neater.
Update
As requested, here are the domain entites that the above mappings represent.
Two subclasses with shared parent
public class A
{}
public class B : A
{
public virtual string BProperty { get; set; }
}
public class C : A
{
public virtual string CProperty { get; set; }
}
Subclass of a subclass
public class A
{}
public class B : A
{
public virtual string BProperty { get; set; }
}
public class C : B
{
public virtual string CProperty { get; set; }
}
Comments 15
Very nice changes James. You’ve been a whirlwind of Fluent NHibernate activity this last week or so. You are doing a stellar job.
Posted 05 Jan 2009 at 12:38 am ¶Could you post what your class objects would actually look like for these mappings?
Posted 05 Jan 2009 at 4:46 am ¶@Paul: Thanks Paul, I put Christmas to good use for once
@Chris: I’ve updated the post with the domain entities, but they’re pretty simple really.
Posted 05 Jan 2009 at 12:43 pm ¶Hi,
Posted 06 Jan 2009 at 10:52 pm ¶there is a little bug, if you try to add a version column to the ClassMap, the tag in the xml file is added before the discriminator tag and therefore raising an exception (the discriminator tag has to be directly below the id tag)
@Harold: Thanks for that, I’ll create an issue for it and we’ll tackle it as soon as we can.
Posted 06 Jan 2009 at 10:55 pm ¶Great work. I am really loving using this.
Posted 20 Jan 2009 at 5:55 pm ¶I noticed a bug where .DiscriminateSubClassesOnColumn(”ColumnName”) still tried to use a string type for the column. It does work with a default as .DiscriminateSubClassesOnColumn(”NetworkTypeID”, 0).
I’ve also been working on some enhancements to the test framework. When I get them working I’ll pass them on.
Oops. With encoding included.
Posted 20 Jan 2009 at 5:57 pm ¶I noticed a bug where .DiscriminateSubClassesOnColumn<int>(”ColumnName”) still tried to use a string type for the column. It does work with a default as .DiscriminateSubClassesOnColumn(”NetworkTypeID”, 0).
public MapSample() { Id(x => x.Id); //stringa da un type DiscriminateSubClassesOnColumn("Type") .SubClass<B>(m =>{ m.Map(x => x.BProperty); }) .SubClass<C>(m =>{ m.Map(x => x.CProperty); }); } public class A :entity.Entity /*Entity holds the Id */ {} public class B : A { public virtual string BProperty { get; set; } } public class C : A { public virtual string CProperty { get; set; } }This little Fixture is required -pun intended. Admittedly it’s obvious, yet… Thank you, I like it.
Posted 11 Feb 2009 at 8:26 am ¶Interessante Informationen.
Posted 06 Mar 2009 at 3:27 am ¶I’m trying to work out the following scenario with regards to Fluent NHibernate notation for the following:
public class A { }
public class B : A { }
public class C : B { }
public class D : B { }
Where the persisted data for class B, class C and class D are all stored in different tables to A.
If the discriminator for type C and D is stored in table B and is a simple char field, what notation is required to:
1) Allow for a 1-to-1 relationship between the parent and subtype record in table B and table C
Posted 18 Mar 2009 at 4:17 pm ¶2) Allow for a 1-to-1 relationship between the parent and subtype record in table B and table D?
How do you do the same with .hbm files? meaning, 1 .hbm file per sub class (can ignore the super class) ? Its like, all 3 classes mapped to 1 table, but in 2 hbm files? (hope you know what i meant).
Posted 25 Mar 2009 at 7:13 pm ¶Sorry but your comment got stuck in limbo for a bit there. I’d suggest you hit the mailing list for support as you’re much more likely to get a response.
As for your particular question, I’m afraid you’re out of luck right now. We don’t currently support that scenario, but we are very much aware of a need for it.
Posted 30 Mar 2009 at 5:00 pm ¶How can I to create a mapping when a Person can be Employee and/or Customer and/or Supplier, using FNH?
Posted 23 Apr 2009 at 6:10 pm ¶Please ask on the Fluent NHibernate mailing list.
Posted 27 Apr 2009 at 11:34 am ¶Hi James,
When using this approach, only table A is created for all given types.
How can I have a table per subtype using this synthax?
Posted 26 May 2009 at 10:56 am ¶Post a Comment