8

Dans mon application, j'ai besoin de parler à plusieurs bases de données. Je gère cela dans NHibernate en créant une SessionFactory par base de données (je suppose que c'est la bonne chose à faire). J'ai donc deux ensembles de modèles (un par base de données), et deux ensembles de mappings Fluent NHibernate ClassMap<>. Les deux sont dans le même projet (séparés par un espace de nom) et j'aimerais le garder comme ça.Comment ajouter des mappages par espace de noms dans Fluent NHibernate

Le problème survient lors de la création de SessionFactory. Pour autant que je peux voir, Fluent NHibernate a essentiellement deux méthodes pour ajouter des mappings:

.Mappings(m => m.FluentMappings.AddFromAssemblyOf<UserClassMap>()) 
    .Mappings(m => m.FluentMappings.Add<UserClassMap>() 

Si j'utilise la première surcharge, puis mes usines de session obtenir toutes les correspondances pour les deux bases de données. Si j'utilise la seconde, je dois spécifier chaque ClassMap individuel. Je voudrais quelque chose comme FluentMappings.AddFromNamespace(). Y a-t-il un moyen de faire cela?

Répondre

16

Il est étrange que FluentNHibernate prend en charge ce type de filtrage pour AutoMapping, mais pas pour ClassMap s. Il ne devrait pas être trop difficile d'ajouter cette fonctionnalité par la magie des méthodes d'extension. Essayez ceci:

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; 
} 

... et l'utiliser comme ceci:

m.FluentMappings.AddFromAssemblyOf<UserClassMap>(t => t.Namespace.StartsWith("One.Of.The.Two.Namespaces")); 
+0

+1 J'ai découvert quelque chose de similaire, mais cette approche est plus générale. –

+1

Cela ne mappe pas SubClassMaps, car ils ne sont pas assignables à partir de IMappingProvider. http: // stackoverflow.com/a/6207141/206297 a une liste étendue de MappingProviders qui devrait être vérifiée. – ngm

0

Il n'y a aucun moyen de le faire. Je recommande de séparer les espaces de noms dans des projets distincts. Mémoriser:

Espaces de noms séparés, même projet lorsque la séparation logique est logique. Séparez les espaces de noms, séparez les projets lorsque la séparation physique a du sens.

Dans ce cas, étant donné que vous ne pouvez pas séparer par espace de noms dans les mappages nhibernate, la séparation physique est logique. Vous pouvez, cependant, contourner cela avec des automaps fluides qui utilisent une configuration .Where ou une configuration ShouldMap. Recherchez les automaps courants et voyez si cela peut vous mener là où vous voulez être.

0
... AutoMap.AssemblyOf<Person>().Where(x => x.Namespace.EndsWith("Domain")) ... 
+0

Je n'utilise pas les automappings, je spécifie mes mappages explicitement avec les mappages ClassMap <>. –

10

J'ai fini par écrire une méthode d'extension qui fait cela pour moi. Fondamentalement, il utilise la réflexion pour itérer sur tous les types qui m'intéressent, et les ajouter un par un. Il est basé sur la mise en œuvre de AddFromAssemblyOf. Utilisation:

.Mappings(m => m.FluentMappings.AddFromNamespaceOf<UserClassMap>()) 

Mise en œuvre:

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); 
    } 
} 

Avertissements:

  • Le nom est un peu trompeur, car il recherche un seul ensemble. Il devrait peut-être s'appeler AddFromAssemblyAndNamespaceOf, mais c'est un peu bavard.
  • Il n'est pas entièrement pérenne. Si les futures versions de FNH ajoutent ou suppriment certaines interfaces mappables, elles ne les incluront pas.

Mais cela fonctionne pour mes fins.

+0

+1 Merci, très utile! –

+0

C'est exactement ce dont j'avais besoin - merci! Cela devrait juste être intégré dans FNH. –