In part 1 we found out how to generate a mapping file using c# and Linq To XSD. In this post we will extend that to show the use of conventions.
The first thing we need an automapping framework to do is to create a class element in our xml mapping file for each of the entity types in our project. We will need a list of the entities in our project:
var types = typeof(User).Assembly.GetTypesSafe().Where(t.Namespace.StartsWith("Servit.Domain.Entities")).ToList();
var mappingXDoc = new hibernatemapping();
foreach (var type in types)
{
var @class = new @class()
{
name = type.AssemblyQualifiedName,
table = type.Name + "s", //feel free to use a more advanced pluralization method (http://bit.ly/b98JK6) – adding an s works for me!
};
mappingXDoc.@class.Add(@class); //LINQ to XSD didn't pluralize the @class collection,
//it might have been better if it generated mappingXDoc.classes instead of mappingXDoc.@class...
}
A pretty simple convention, but it will do for now. So far we have a mapping document with all our classes, but they are all empty – no properties! We need some conventions. The idea is that these conventions should be easy peasy to write so that you don’t need a big framework like FNH to get your mapping written.
Imagine we want to add conventions to do the following:
Lets suppose we have an interface IClassConvention. We’re going to get hold of the conventions and apply them to the mappingXDoc variable we defined in the bootstrap code from part 1. Note the use of the TopologicalSort method from another of my posts, called via an extension method, because we want the conventions to execute in a certain order.
//get all the convention types in our assembly
var conventions = typeof(IClassConvention).Assembly.GetTypesSafe()
.Where(t => typeof (IClassConvention).IsAssignableFrom(t))
.Where(t => t.CanBeInstantiated()) //check they aren't abstract or have open generic types
.TopoSort((t, potentialTypes) => potentialTypes.Where(pt => typeof (IRunAfter<>).MakeGenericType(t).IsAssignableFrom(pt)))
.Select(t => (IClassConvention)Activator.CreateInstance(t)).ToList(); //and instantiate them
foreach (var convention in conventions)
{
foreach (var type in types)
{
var @class = mappingXDoc.@class.Single(c => c.name == type.AssemblyQualifiedName);
convention.Apply(type, @class, types, mappingXDoc);
}
}
OK, so we haven’t got any conventions yet, but you can see how we call them and apply them. This is pretty much the whole “framework” right there. As you can see, there isn’t much to it. With this little code, you should be able to start writing your own convention framework, tailored specifically to your classes and database schema.
In the next post, we’ll implement a convention or two, and link to a sample project.