如何在Fluent NHibernate中通过命名空间添加映射

时间:2011-06-01 16:25:33

标签: nhibernate fluent-nhibernate nhibernate-mapping fluent-nhibernate-mapping

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

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

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

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

4 个答案:

答案 0 :(得分:16)

很奇怪,FluentNHibernate支持这种类型的自动化过滤,但不支持ClassMap。不过,通过扩展方法的神奇之处,自己添加此功能应该不会太难。试试这个:

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

答案 1 :(得分: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的未来版本添加或删除某些可映射接口,则不会包含它们。

但它适用于我的目的。

答案 2 :(得分:0)

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

单独的命名空间,逻辑分离有意义的同一项目。 在物理分离有意义时,单独的命名空间,单独的项目。

在这种情况下,由于您无法在nhibernate映射中按名称空间分隔,因此物理分离是有意义的。但是,您可以使用使用.Where或ShouldMap配置的流畅自动机来解决这个问题。查找流畅的自动化程序,看看它是否可以帮助您达到目标。

答案 3 :(得分:0)

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