In my application, I need to talk to multiple databases. I am handling this in NHibernate by creating one SessionFactory per database (I assume this is the correct thing to do). So I have two sets of models (one per database), and two sets of Fluent NHibernate ClassMap<>
mappings. Both are in the same project (separated by namespace) and I'd like to keep it that way.
The problem comes when creating the SessionFactory. As far as I can see, Fluent NHibernate has basically two methods for adding mappings:
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<UserClassMap>())
.Mappings(m => m.FluentMappings.Add<UserClassMap>()
If I use the first overload, then my session factories get all the mappings for both databases. If I use the second, I have to specify each individual ClassMap. I'd like something like FluentMappings.AddFromNamespace()
. Is there a way to do this?
It's odd that FluentNHibernate supports this type of filtering for automapping, but not for ClassMap
s. It shouldn't be too hard to add this feature yourself, though, via the magic of extension methods. Try this:
public static FluentMappingsContainer AddFromAssemblyOf<T>(
this FluentMappingsContainer mappings,
Predicate<Type> where)
{
if (where == null)
return mappings.AddFromAssemblyOf<T>();
var mappingClasses = typeof(T).Assembly.GetExportedTypes()
.Where(x => (typeof(IMappingProvider).IsAssignableFrom(x)
|| typeof(IExternalComponentMappingProvider).IsAssignableFrom(x))
&& where(x));
foreach (var type in mappingClasses)
{
mappings.Add(type);
}
return mappings;
}
... and use it like this:
m.FluentMappings.AddFromAssemblyOf<UserClassMap>(t => t.Namespace.StartsWith("One.Of.The.Two.Namespaces"));
I wound up writing an extension method that does this for me. Basically it uses reflection to iterate over all the types I'm interested in, and add them one-by-one. It is based on the implementation of AddFromAssemblyOf
. Usage:
.Mappings(m => m.FluentMappings.AddFromNamespaceOf<UserClassMap>())
Implementation:
public static class FluentNHibernateExtensions
{
public static FluentMappingsContainer AddFromNamespaceOf<T>(
this FluentMappingsContainer fmc)
{
string ns = typeof(T).Namespace;
IEnumerable<Type> types = typeof(T).Assembly.GetExportedTypes()
.Where(t => t.Namespace == ns)
.Where(x => IsMappingOf<IMappingProvider>(x) ||
IsMappingOf<IIndeterminateSubclassMappingProvider>(x) ||
IsMappingOf<IExternalComponentMappingProvider>(x) ||
IsMappingOf<IFilterDefinition>(x));
foreach(Type t in types) {
fmc.Add(t);
}
return fmc;
}
/// <summary>
/// Private helper method cribbed from FNH source (PersistenModel.cs:151)
/// </summary>
private static bool IsMappingOf<T>(Type type)
{
return !type.IsGenericType && typeof(T).IsAssignableFrom(type);
}
}
Caveats:
AddFromAssemblyAndNamespaceOf
, but that's a little verbose.But it works for my purposes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With