NHibernate 3.2 will come with its own embedded mapping by code.
If you want know it is not based in fluent-interface, instead it is based on “loquacious”. That said you should understand that it has nothing related with Fluent-NHibernate.
The main idea under the NHibernate’s “sexy mapping” came from my dear ConfORM. In the past year the no conformist red man was running a lot and now I’m ready to transfer most of ConfORM’s intelligence directly inside NHibernate. To continue reading this post you have to run this song.
It’s simple (I’m too sexy)
Simple model
{
public int Id { get; set; }
public string Something { get; set; }
}
Simple mapping
mapper.Class<MyClass>(ca =>
{
ca.Id(x => x.Id, map =>
{
map.Column("MyClassId");
map.Generator(Generators.HighLow, gmap => gmap.Params(new { max_low = 100 }));
});
ca.Property(x => x.Something, map => map.Length(150));
});
It’s flexible (I’m too sexy for my application)
You can organize your mapping as you want, class-by-class, different concerns about a class in different places and so on… (yes!! if you are a ConfORM user you know the concept)
mapper.Class<MyClass>(ca =>
{
ca.Id(x => x.Id, map =>
{
map.Column("MyClassId");
});
ca.Id(x => x.Id, map =>
{
map.Generator(Generators.HighLow, gmap => gmap.Params(new { max_low = 100 }));
});
ca.Property(x => x.Something);
ca.Property(x => x.Something, map => map.Length(150));
});
As you can see there is no problem duplicating the declaration of a mapped element and you can even do the same with the whole mapping of a class in two different places:
{
ca.Id(x => x.Id, map =>
{
map.Generator(Generators.HighLow, gmap => gmap.Params(new { max_low = 100 }));
});
ca.Property(x => x.Something);
});
mapper.Class<MyClass>(ca =>
{
ca.Id(x => x.Id, map =>
{
map.Column("MyClassId");
});
ca.Property(x => x.Something, map => map.Length(150));
});
It’s conventions friendly (too sexy by far)
You can apply “democratic” conventions
mapper.BeforeMapClass +=
(mi, t, map) => map.Id(x => x.Column((t.Name+"id").ToUpper()));
mapper.BeforeMapProperty +=
(mi, propertyPath, map) => map.Column(propertyPath.ToColumnName().ToUpper());
mapper.Class<MyClass>(ca =>
{
ca.Id(x => x.Id, map => { });
ca.Property(x => x.Something);
});
or you may want “republican” conventions
mapper.AfterMapClass +=
(mi, t, map) => map.Id(x => x.Column((t.Name + "id").ToUpper()));
mapper.AfterMapProperty +=
(mi, propertyPath, map) => map.Column(propertyPath.ToColumnName().ToUpper());
mapper.Class<MyClass>(ca =>
{
ca.Id(x => x.Id, map => map.Column("Whatever"));
ca.Property(x => x.Something, map => map.Column("Whatever"));
});
NHibernate 3.2 too sexy by far!!!
Cool!! And the time to read (and understand) this post is more or less the same that the length of the "too sexy" song. ;-)
ReplyDeleteVery nice!
ReplyDeleteWill it cover the full HBM specification?
One thing that would be very cool is the ability to map named queries as LINQ functions!
By the way, haven't seen any reference to the new feature...
@rjperes
ReplyDeleteYou didn't see references because we are still waiting your patch for the reference manual.
what you are waiting for ?
Well, at least I'd have to see what it looks like... by references I mean a piece of code...
ReplyDeletewell... I don't know where you are looking, that code is already in NHibernate sources.
ReplyDelete...just committed, it wasn't there when I looked!
ReplyDeleteNice joke, happy fools day
ReplyDeleteI'm sorry for you but it is not a joke, the code published here are passing tests in NHibernate repository.
ReplyDeleteI'm curious why you chose to create a new mapping interface instead of using the existing Fluent NHibernate project's interface. I realize fluent nhibernate still generates the XML but it seems like you could have simply adapted their interface to not require the XML such as you have done with your own code mapping
ReplyDeleteFNH is not so sexy at least for me.
ReplyDeleteNow the FNH team can use the embedded API and enjoy it with all its features.
Hi Fabio,
ReplyDeleteHow much of ConfOrm (btw, I love it, thanks for it!) will the new sexy mapping have? I'm starting a new project and I'm using it as my current mapping of choice, so now I'm wondering now how much refactoring will will be waiting for me by 3.2 release! Oh, and besides, will you continue supporting ConfOrm as it is today?
Thanks for doing such a great job. I really appreciate this style of mapping!
ReplyDeleteOne thing I would like to know:
Is is possible to derive mappings, like I can in FNH? Usually I have at least an abstract class "EntityBase" which has some generic properties like Id or ModifiedDate. Do I need to write the mapping code for those again and again for each derived class?
Do you think it is wise to combine xml mappings and this approach.
ReplyDeleteI have about 3 years worth of xml mappings. ? Refactoring them would be not cost effective.
Any advice on a best of both worlds solution
BTW, are automappings on your roadmap, or isn't is sexy enough? ;-)
ReplyDeleteThis comment has been removed by the author.
ReplyDelete@Paul Cowan if you have investment in xml mapping you might like to try out my mapping approach using LinqToXSD to generate a library for manipulating the xml mappings, which feels a lot like working with the xml mappings see http://dl.dropbox.com/u/2808109/blog/nhmapping/xml%20vs%20linqtoxsd.png for mapping 101. Obviously it can be improved using reflection to build up the strings.
ReplyDelete@rjperes - some automapping goodness in my project too!
Github link: https://github.com/mcintyre321/NhCodeFirst
This comment has been removed by the author.
ReplyDeleteHi Fabio, thanks for sharing the code snippets.
ReplyDeleteSo, is the AfterMap...() set of methods intended to be the way of doing automapping / mapping-by-convention?
Also, is there a way to do mapping as mapping-class-per-entity not all in one place?
@Harry:
ReplyDeleteYou mean the posts on adverse conditionals from july 2010? I will look at the code, thanks! And keep on writing... :-)
heh, that was some posts on the concept. The stuff on github is what I've been working on since, so don't let the sell-by date put you off!
ReplyDeleteIs it possible with the new API to create mapping where an Id is not mapped to any property of a class?
ReplyDeleteCan it map to Oracle UDT's ?
ReplyDeleteHi, this loquacious api for mapping is great. I've begun to use it and is very intuitive. But, I have a problem, I need to map the same class like both Entity and Component, but it throws a MappingException "Ambiguous mapping"
ReplyDeleteis it possible to specify naming strategies with properties & IDs?
ReplyDeleteIs this a NH specific thing, or is it also supported in Java's Hibernate? (Though it'shard to think how it would be though considering its lack of lambda)
ReplyDeleteCan you give example of mapping dynamiccomponent by code?
ReplyDeleteHere it is
ReplyDeletehttps://github.com/nhibernate/nhibernate-core/blob/master/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/DynamicComponentMappingTests.cs
It cost me an hour to understand that parameter should have name "max_lo" not "max_low" :)
ReplyDeleteHello
ReplyDeleteHow can we use stored procedure with that type of mapping ?
Or can we mix mapping by code and by hbm.xml ?
Regards
Hi, how do I do a Table per class mapping using mapping by code?
ReplyDeleteUse this as a reference for all mapping issues: http://knol.google.com/k/nhibernate-chapter-8-inheritance-mapping#8(2E)1(2E)2(2E)(C2)(A0)Table_per_subclass
ReplyDeleteTable-per-class can be achieved like this:
var mapper = new ModelMapper();
mapper.Class(m =>
{
// some mapping goes here (i.e. m.Id)
});
mapper.JoinedSubclass(m => {
m.Table("ChildTable"); //this is optional
m.Key(k => k.Column("ReferencedId")
});
hello
ReplyDeletehow do you add allow-imports to your class with nhibernate 3.2's mapping by code ?
Hello
ReplyDeleteI need to map single class with different tables
class ClassMapper : ClassMapping
{
public ClassMapper()
{
Type type = typeof(Tdiff);
this.EntityName(type.Name);
Id(x => x.Id);
Property(x => x.Name);
Table(type.Name);
}
}
but this class map creates the single mapping or single table ,even i call this mapper many times by passing different types
any solution?
Hey Fabio - quite a different question. Where does "loquacious interface" term come from? Have you made it up? Or is it used somewhere already and described, like Martin Fowler's on fluent interface? Do you know other APIs based on that kind of interface?
ReplyDelete@Adam
DeleteMost of implementations of "fluent interface" are not so "fluent"... instead they are more loquacious than XML.
That's right. I'm curious have you seen the term "loquacious interface" used somewhere before mapping-by-code?
DeleteHey Fabio
ReplyDeleteIf i add properties dynamically in Persistent class and save .
as after i want to retrieve those values by Get or Query..
is it possible? Any way...
This comment has been removed by the author.
ReplyDeleteHello! So if my assumption is correct that the mapping is permanent from this point on, how do you undo a mapping (to make it truly "dynamic" :)), say if you had a "main" mapping and you wanted to use a dynamic 1 temporarily/for a particular scenario, then revert to "main"? We have this scenario where a dev inadvertently added an add'l mapping to a subclass who's parent was already mapped, such that when we accessed any(un"discriminator"ed) fields of the parent's mapping that wasn't in the new child's, the new child's mapping superseded/hid those mappings/produced NH "not mapped" exceptions. From that time, devs unaware of the new child mapping would respond to the "not mapped" errors by simply adding (in essence, duplicating) the fields to the new mapping to avoid the error. Did give me an idea tho, that this could come in handy - if I could "undo" it after the specific db interaction - w/out having to touch all the existing mappings to make them dynamic as well (which I guess would also solve the problem). Sorta "just-in-time, discriminator-less" dynamic mappings.
ReplyDelete