Make hbm2net generated code look more like .NET 2.0
NHibernate ships with a pretty simple but effective code generator console program named hbm2net. Unfortunatelly it does not use any .NET 2.0 features yet. So I just tried to at least get in partial classes which is a great feature to separate the autogenerated code with any custom changes.
Go to www.hibernate.org and download the nhibernate framework. I strongly recommend though, to get the svn version to get the latest hbm2net version. The one shipped with the stable branch is not that great and this little guide uses the trunk of the svn on June 17, 2006.
What do we need to do? It should be fairly simple to introduce parital classes since we only have to change the filename the class is stored under (from xyz.cs to xyz.base.cs or xyz.hbm2net.cs) and introduce an additional partial at the position of any class modifiers. Hopefully there will be a basic template or any programmatically introduced modifiers. In addition, if there is time, I want to introduce a mechanism that automatically generates the corresponding xyz.cs, if it does not yet exist. So, let's dive in.
Introducing partial
Oh, great. The tool uses Velocity to generate the classes. Great, great, great. Well, that should make it fairly easy to do the modifications. A short runthrough: there is a convert.vm that is used as a template for the class generation. So one solution would be to edit this line:
$clazz.scope $clazz.modifiers $clazz.declarationType \
$clazz.generatedName [...]
to something like this:
$clazz.scope #if(!$clazz.isInterface())partial#end $clazz.modifiers \
$clazz.declarationType $clazz.generatedName [...]
That would be fine. Since I knew where to look, when I found out that the generator uses Velocity, this solution gets 10 points for speed but only 2 points for elegance.
Since "partial" is a class modifier it should be inserted into the template by $clazz.modifiers and not hardcoded. Plus, I have some time on my hand, and I want to learn more about hbm2net. So those 2 points for elegance are more out of curiosity than out of spite. ![]()
Ohoh, I guess this should go on my ever-so-long todo list. Damn this is weird codebase. It is very, very obvious that this was "ported" from Hibernate. Hehehe. Some quite nasty quickhacks to port stuff as well. One class is still called JavaTool.
Oh, well.
The class we have to focus on is ClassMapping. This class is used to resolve everything prefixed with $clazz. in the convert.vm file. (Take a look at VelocityRenderer.render(...) to verify that). Therefore we need the property Modifiers to change the behaviour of $clazz.modifiers. The original one looks like this:
- virtual public string Modifiers
- {
- get
- {
- if (shouldBeAbstract() &&
- (Scope.IndexOf("abstract") == -1)
- )
- {
- return "abstract";
- }
- else
- {
- return "";
- }
- }
- }
So we simply create a new class PartialClassMapping that inherits from ClassMapping and overwrites the Property Modifiers with something like:
- public override string Modifiers
- {
- if (Interface)
- {
- return base.Modifiers;
- }
- else
- {
- if (base.Modifiers.Trim() == string.Empty)
- {
- return "partial";
- }
- else
- {
- return "partial " + base.Modifiers;
- }
- }
- }
Be sure to create the right Constructors that simply call base. Download the whole file: PartialClassMapping.cs
Well, now there should be some configuration system. Or a Factory of Strategy Pattern that creates new instances of the appropriate ClassMapping... Hmpf. Well, there are only two files that contains "new ClassMapping" and those are ClassMapping itself and CodeGenerator. So, we introduce a couple of ugly protected virtual methods there to make the CodeGenerator the real keeper of the "configuration" of with classes will be generated.
After some reordering of the Constructors' arguments and refactoring those things worked out - kinda.
Now there is a new command-switch "--net20" that will enable those first tiny .NET 2.0 features. But I guess later there should be Generics involved, when using that switch, etc.
Here are all the downloads for this hack:
PartialClassMapping.cs
ClassMapping.cs
CodeGenerator.cs
And introducing the base class - that's tomorrow. ![]()
Continue here for the second part. Third part.

[...] I did not pursue the plan I had in my first part about extending hbm2net. Instead Roland Eichler, a fellow programmer, and I decided to write a totally independant Renderer for hbm2net. We are using CodeDOM’s CodeGenerator and right now the Renderer is utilizing partial classes and does feature Generics. Please bear with us, until we can present the results. Hopefully next week. June 19th, 2006 8:16 pm – Programming, .NET, C#, IT, ORM, NHibernate [...]
Pingback on June 19, 2006 @ 20:16:50
Thanks for the post and code, I’ve managed to get it working with the current NHibernate version and I’ve managed to get most of my code that was implemented on NHibernate 1.0.4.0 converted to use the new generated classes (I’ve not enabled the Generics yet.. all in due time). I’ve got one question that’s probably more NHibernate related but maybe you can help? The new generated files are not [Serializable] and this is a problem when I’m using caching. Is there a simple way to get the generated code to be Serializable (I don’t want to add partial files just to get this functionality – I know this will also solve the problem)?
Any idea if this generator will become part of NHibernate? I’ll go bug them on this too.
Comment on April 17, 2007 @ 12:53:23
Hey Gean,
at first: Thanks for your comments. And for trying out the code.
Solution is based on the code described here:
http://saftsack.fs.uni-bayreuth.de/~dun3/archives/hbm2net-generate-code-nhibernate-codedom/55.html
To solve your problem: Use a CodeAttributeArgument to declare generated classes as Serializable.
http://msdn2.microsoft.com/de-de/library/system.codedom.codeattributeargument(VS.80).aspx
In the code before “myNamespace.Types.Add(ctd);” in CodeDOMRenderer.cs insert:
if (ctd.IsClass)
{
CodeAttributeDeclaration codeAttrDecl = new CodeAttributeDeclaration(“System.Serializable”);
ctd.CustomAttributes.Add(codeAttrDecl);
}
–
It is not foolproof, you should probably also check if the class is abstract. But at least it makes the generated classes Serializable. Is that enough for you?!
Anyway: As far as I know, it is not too good an idea to use the NHibernate-objects for serialization. And I am not too sure what kind of caching you are using that requires Serializable? I would love to have some more input from you on the subject.
Please see here for reasons agains serializing NH-objects directly, we could certainly look into generating DTOs automatically that would be serializable:
http://www.thescripts.com/forum/thread566580.html
And on the subject of becoming a part of NHibernate: For now we agreed on it not being in NH. So don’t bug them too much.
I don’t have the time to support it too much right now as I am in the “hot” last phase of my studies.
Hoping to hear back from you!!
Tobi
Comment on April 17, 2007 @ 22:21:44
You link around why not to serialize VO’s definitly makes food for thought.
The need for serialization is two fold:
1) I’ve not delved to much into it but it like seems the Prevalence Cache requires the VO’s to be serilizable, I thought it made sense since the VO’s are cached onto HDD. But I guess if one day I get time I can investigate a bit further.
2) The ASPX pages do caching that also require serilizing. This is where I will need to look into exactly into why my design seem to differ from most other.
I’ve managed to figure out how to modify the code to generate serilizable classes. Thanks for the advice, I’ll add it as a meta tag once I decide to stick with the generator, and I’ll contribute it back to your codeset (one good reason to add it to NH project, so at least I’m looking at the latest/greatest)?
Good luck at the studies.
Comment on April 18, 2007 @ 10:10:22
Hi!
I want to extend my SQL experience.
I red that many SQL resources and want to
read more about SQL for my occupation as mysql database manager.
What would you recommend?
Thanks,
Werutz
Comment on October 8, 2008 @ 05:35:58
You can use source4dotnet ‘s code generator engine which has templates so similar to the Nhibernate’s approach and it has eradicated the complexitites of working with Nhibernate.
It’s located here : .Net Code Generator
Comment on January 24, 2009 @ 16:04:56