I’ve just committed a rather large update to the Fluent NHibernate conventions code. This post explains why I’ve done this, and gives you some starting points to update your code. Anything else you need can be found on the wiki under conventions and converting to new-style conventions.
So why have I rewritten conventions? Our original implementation was simple, but not really maintainable into the future. It was a single class that was a major violation of separation of concerns, and it just kept growing and growing. It didn’t gracefully degrade either; if we didn’t have the exact convention you needed it was tough luck, there was very little you could do short of modifying the code yourself.
Our original design worked something like this:
.WithConventions(conventions =>
{
conventions.TableName = type => type.Name + "Table";
conventions.DefaultLazy = true;
})
As you can see, it’s a fairly simple design. Lambda functions were set that got called in various places throughout the mapping generation cycle. It was a good design for simple scenarios; however, when you start overriding more conventions, and introducing logic into them, it can quickly become a massive ball of mud. So while there was an initial simplicity to it, that simplicity was quickly lost if you were trying to do anything clever with it. This is another thing that the rewrite aims to solve.
So how have things changed? The ability to define conventions inline is gone, for starters. Instead what you have is a series of interfaces of varying degrees of granularity; any classes implementing any of the interfaces will be automagically hooked into the mapping generation cycle. What this equates to is you’ll have a folder/namespace in your projects dedicated to conventions, each class making an alteration to the conventions when it’s called. As each convention is an interface, it means you can implement multiples of them in a single class, which allows you to group common conventions into a single class if you desire.
Example: Customising the table name
public class TableNameConvention : IClassConvention
{
public bool Accept(IClassMap classMap)
{
return true; // apply to all mappings
}
public void Apply(IClassMap classMap)
{
// will produce table names like: tbl_Customer, tbl_Product
classMap.WithTable("tbl_" + classMap.EntityType.Name);
}
}
This is a simple implementation of the IClassConvention interface, which is applied to all class mappings (hence the return true in Accept) and simply prefixes the table name with tbl_.
Example: Adding your conventions
There’s one thing you need to do to get Fluent NHibernate to use your conventions, and that’s to inform the convention discovery mechanism of where it’s to search for conventions. You do this using the PersistenceModels CovnentionFinder property, or through the ConventionDiscovery property through Fluent Configuration.
Fluently.Configure()
.Mappings(m =>
{
m.FluentMappings
.AddFromAssemblyOf<Entity>()
.ConventionDiscovery.AddFromAssemblyOf<MyConvention>())
})
That’s all there is to it really, certainly from a users perspective anyway. The architecture is designed in such a way that you have a much greater control of the granularity of your conventions; if you need a convention we haven’t explicitly supplied, you can use the convention “above” the one you want, and implement it yourself. If you need a convention for just Bag collections (which we don’t have one for), you just need to create an implementation of IHasManyConvention and limit it to bags. Easy.
Some shortcuts
I realise that the new design is more verbose than it was originally, and if your scenario really is one that only uses one or two conventions, then the new design might be too much for you. To cater for you people, I’ve created some basic inline support. I really don’t recommend you use these unless you’re doing something really simple. Separation is always preferred.
There’s the ConventionBuilder class which has several static properties (Class for example, there’s one for each convention) which allow you to create an inline convention.
ConventionBuilder.Class.Always(x => x.SetAttribute("something", "true"))
ConventionBuilder.Id.Always(x => x.ColumnName("ID"))
ConventionBuilder.Property.When(
x => x.Property.PropertyType == typeof(int),
x => x.ColumnName(x.Property.Name + "Num")
)
These can be used directly in the ConventionDiscovery property mentioned above; it has an Add method that can take a params array of conventions, there’s also a Setup method which can be used for multiple additions.
.ConventionDiscovery.Add(
ConventionBuilder.Class.Always(x => x.SetAttribute("something", "true")),
ConventionBuilder.Id.Always(x => x.ColumnName("ID"))
)
.ConventionDiscovery.Setup(c =>
{
c.AddFromAssemblyOf<MyConvention>();
c.Add(ConventionBuilder.Id.Always(x => x.ColumnName("ID")));
})
In addition to that, there’s a limited selection of very common conventions which can be used inline. Again, I don’t advocate using these for anything complicated. If you start having logic in your conventions, or even if the lambdas end up being multi-line, I’d suggest using the full conventions. These helpers live in the FluentNHibernate.Conventions.Helpers namespace.
Table.Is(x => "tbl_" + x.EntityType.Name)
PrimaryKey.Name.Is("ID")
DynamicUpdate.AlwaysTrue()
These can be used in the same way as the ConventionBuilder above.
Regarding auto mapping
The auto mapper uses a small subset of conventions to discover various parts of your mappings. It was originally the case that these special conventions were lumped in with the rest of the conventions, even though you couldn’t use them outside of the automapper. As the old style conventions have gone, the automapper now has a separate set of conventions (they’re the same ones, just moved) that it uses. So in addition to the ConventionDiscovery property, the auto mapper has a WithSetup method that you can use to configure the auto mapping specific ones (IsBaseType primarily).
Further reading
So this post should have given you a basic introduction to the changes I’ve made. To go further, you’re going to have to know what interfaces are available to implement. You should probably also read the general conventions wiki, how to convert your existing conventions to the new style, and the convention shortcuts if it interests you. For maintainers, or just curious people, there’s also the wiki on how the conventions work behind-the-scenes.
Trackbacks...
- Pingback from Rolling my own blog engine, part 3 — CarlFurrow.com

Comments...
James, you ahve a typo
public bool Apply(IClassMap classMap)
{
// will produce table names like: tbl_Customer, tbl_Product
classMap.WithTable(“tbl_” + classMap.EntityType.Name);
}
wither this method is meant to be void or its missing a return value.
Why not create a DelegateConvention like
public class DelegateConvention : IClassConvention
{
public DelegateConvention(Func accept, Action action){…}
…
}
By Harry M — 3 Mar, 2009 @ 9:31 am
Thanks Harry, corrected. Take a look at the conventions shortcuts which uses an underlying delegate convention.
By James Gregory — 3 Mar, 2009 @ 9:37 am
Man, this is a LOT better. Well done, James!
By Ben Scheirman — 3 Mar, 2009 @ 11:57 am
James: It’s time for a book. Manning would probably be interested. Get a co-author if needed. Get the code baked, write the book! I’ll be the first to buy it and write a review on our site. You have the skills and your writing style is perfect for this. How about it?
By Peter Bromberg — 3 Mar, 2009 @ 1:42 am
Hey Peter, I’m very flattered you think I’ve got a book in me; once the code-base stabilises and we start catching up to hbm.xml in features then I’d certainly be open to the possibility. We’ll see what the future holds.
By James Gregory — 3 Mar, 2009 @ 8:19 am
Hi – I agree with the convention changes and feel this is definitely a step in the right direction.
I am only just starting to use FluentNhibernate and only just got to grips with the previous conventions though and how these were implemented. To get me on the right track could you advise how the following would be implemented using the above technique:
.WithConventions(c =>
{
c.GetForeignKeyName = type => type.Name + “Id”;
c.GetForeignKeyNameOfParent = type => type.Name + “Id”;})
I know you have to use the IHasManyCollection but not sure the best way to approach it – I know it is probably very simple but any help appreciated. This would probably be useful as another example in Wiki as it a commonly used convention and its not initially obvious how to use the new conventions to acheive this. Great project by the way..
By Mark — 3 Mar, 2009 @ 12:59 pm
Hi Mark, sorry but your comment got stuck in comment-limbo. Your points are great and those two conventions should be included in the Wiki. I’d recommend you pop by the mailing list if you’re in need of any help.
By James Gregory — 3 Mar, 2009 @ 4:59 pm
Post a comment...