Spicing up our NHibernate Fluent Interface with pluggable conventions

I’m adding pluggable type conventions to our NHibernate mapping Fluent Interface today:

 

    public interface ITypeConvention
{
bool CanHandle(Type type);
void AlterMap(IProperty property);

}

public interface IProperty
{
void AddAlteration(Action action);
void UseThisType() where T : IUserType;
void SetAttributeOnPropertyElement(string name, string key);
}
 
Anyway, one of the design ideas we can steal from Ruby on Rails is the convention over configuration philosophy.  Part of the efficiency gain I think we make by moving from hbm.xml configuration to the FI is taking advantage of conventions tied to object types.  We've made the FI smart enough to respond to some class and property types.  The code above is going to make these conventions pluggable.  Today, I'm adding a custom IUserType for our Value Objects.  I'm creating the hook above to plug in a rule that says that any property subclassing type ValueObject will be mapped using this new IUserType.  
 
Here's some examples of conventions: 
  • You're trying to create a mapping for a class that subclasses DomainEntity?  Why don't I just automatically set up the identifier node for you pointing to the Id property.  I'll add property mappings for all those common audit trail columns too.
  • You got an enumeration type?  I'll just stick in an EntityStringType for you.
 
 
More results, less code, and fewer lines of XmHell. 

 


About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in Database and Persistence. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Steinard

    Yeah, but that would involve more steps then observing end users use the software and identifying which use-cases and data mappings should change lazy/eager mappings. At some really big customers, the software installation/security bureaucracy is really complicated and it takes weeks to get a clearance for dropping in a new dll (it took like 6 weeks to get an email account on their site). Getting clearance for editing an already installed xml file is no hassle.

    Sure it must be tested, and that is what we will do after work hours. We also know it will work, because there is no change in relational mappings (and the LazyInitializer will kick in and initialize the object graph when lazy properties are hit in a detached object graph). But will it have the performance impact we hope for?

    My point is that I like the approach of using code to configure the mappings, but I would still have the possibility to save the output as a .hbm.xml file for flexibility. Then I would have more options when a xcopy of a new dll isn’t realistic.

    Cheers,
    Steinar.

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    @Steinard,

    I’ll give you my standard answer to “but we can deploy Xml without compiling.” Make your build process quick and automated, then the copy Xml file thing around isn’t a serious advantage. Besides, it’s not like you can actually deploy an Xml file change without testing anyway.

    You could always gather up your NH config in one assembly and copy that around.

  • Steinard

    Nice, and I also hate those darn xml-files. We use attributes where I work, but the end result is of course those .hbm.xml files. Just one detail though, the .hbm.xml files can be edited without a redeployment of software. This is good for tweaking default fetch plan at a customer site. Customers use our software very differently and sometimes our default optimized fetch plan does not suite the general data load at some customers. So, being able to easily change mappings that should be eager or lazy is a good thing, when hired in for optimization.

    Cheers,
    Steinar.

  • Eduardo

    I got curious about the IUserType and ValueOjbect thing. Is it kind of reusable domain difined type? I was thinking about that the other day.

    What do your user type does? Label, validation, mask …

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    @Tim,

    The Repository in there is very naive at the moment, but we’ll get it real soon. Note the complete absence of the words “try” and “catch” in that code.

    I just wanted a Repository off the bat that could be swapped in and out with an “In Memory” model for whitebox testing.

    I don’t think the two things would collide, and I’m not enthusiastic about creating more assemblies. I am willing to change the code to decouple the FI from everything else if that’s necessary.

    And I’d love to have a volunteer for the NHib FI coding;)

  • http://lunaverse.wordpress.com Tim Scott

    This is really cool. I am starting a new Nhib project and would love to escape XmlHell. I took a quick look at the code. I am trying to figure out what all ShadeTree.DomainModel does. It looks like it also has some repository functionality. I think I plan to use RhinoCommons as well. Any idea if the two would conflict? Is there any way to break the mapping tool into it’s own assembly? I’m happy to help with that it that’s the way to go.

  • http://morten.lyhr.dk Morten Lyhr

    So why dont you install WLW on work Win2008, thats what I did?

  • http://blowmage.com/ Mike Moore

    FWIW, Brad Wilson had a nice post about installing the Live apps on Win2K8.

    http://bradwilson.typepad.com/blog/2008/02/live-apps-on-wi.html

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    @Ayende,

    I’m on Windows 2008 at work. My normal PC with WLW is ill.

  • http://www.ayende.com/Blog/ Ayende Rahien

    Jeremy,
    Use an external tool, like WLW

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    @Will,

    It’s just too much effort to stop CS from eating my code. It’s trying to be helpful and reformat my C# code inside a

     node for me.
    
    Sorry about the Courier New exposure.
  • http://primedigit.com/ Will Shaver

    I think you’re missing some kind of end-code tag, the bottom half of your post is not wrapping correctly.