8

在我的应用程序中,我需要与多个数据库通信。我在 NHibernate 中通过为每个数据库创建一个 SessionFactory 来处理这个问题(我认为这是正确的做法)。所以我有两组模型(每个数据库一个)和两组 Fluent NHibernateClassMap<>映射。两者都在同一个项目中(由命名空间分隔),我想保持这种方式。

创建 SessionFactory 时出现问题。据我所知,Fluent NHibernate 基本上有两种添加映射的方法:

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

如果我使用第一个重载,那么我的会话工厂将获得两个数据库的所有映射。如果我使用第二个,我必须指定每个单独的 ClassMap。我想要类似的东西FluentMappings.AddFromNamespace()。有没有办法做到这一点?

4

4 回答 4

16

奇怪的是,FluentNHibernate 支持这种类型的自动映射过滤,但不支持ClassMaps。不过,通过扩展方法的魔力,自己添加此功能应该不会太难。尝试这个:

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

...并像这样使用它:

m.FluentMappings.AddFromAssemblyOf<UserClassMap>(t => t.Namespace.StartsWith("One.Of.The.Two.Namespaces"));
于 2011-06-01T20:17:07.553 回答
10

我最终写了一个扩展方法来为我做这件事。基本上,它使用反射来遍历我感兴趣的所有类型,并逐个添加它们。它基于AddFromAssemblyOf. 用法:

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

执行:

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

注意事项:

  • 这个名字有点误导,因为它只搜索一个程序集。它也许应该被称为AddFromAssemblyAndNamespaceOf,但这有点冗长。
  • 它并非完全面向未来。如果 FNH 的未来版本添加或删除了一些可映射接口,它不会包含它们。

但它适用于我的目的。

于 2011-06-01T20:19:55.613 回答
0
... AutoMap.AssemblyOf<Person>().Where(x => x.Namespace.EndsWith("Domain")) ...
于 2011-06-01T19:51:33.950 回答
0

没有办法做到这一点。我建议将命名空间分离到单独的项目中。记住:

当逻辑分离有意义时,分离命名空间,同一个项目。当物理分离有意义时,分离命名空间,分离项目。

在这种情况下,由于您不能在 nhibernate 映射中按名称空间进行分隔,因此物理分隔是有意义的。但是,您可以通过使用 .Where 或 ShouldMap 配置的流畅自动地图来解决此问题。查找流利的自动地图,看看是否可以将您带到您想去的地方。

于 2011-06-01T19:47:14.870 回答