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

发布于 2024-11-11 16:43:52 字数 564 浏览 10 评论 0原文

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

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

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

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

骑趴 2024-11-18 16:43:52

奇怪的是 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"));

It's odd that FluentNHibernate supports this type of filtering for automapping, but not for ClassMaps. 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"));
冰火雁神 2024-11-18 16:43:52

我最终编写了一个为我完成此操作的扩展方法。基本上它使用反射来迭代我感兴趣的所有类型,并将它们一一添加。它基于 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 的未来版本添加或删除一些可映射接口,它将不会包含它们。

但它适合我的目的。

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:

  • The name is a little misleading, since it only searches one assembly. It should perhaps be called AddFromAssemblyAndNamespaceOf, but that's a little verbose.
  • It is not entirely future-proof. If future versions of FNH add or remove some of the mappable interfaces, it wouldn't include them.

But it works for my purposes.

深海少女心 2024-11-18 16:43:52
... AutoMap.AssemblyOf<Person>().Where(x => x.Namespace.EndsWith("Domain")) ...
... AutoMap.AssemblyOf<Person>().Where(x => x.Namespace.EndsWith("Domain")) ...
坚持沉默 2024-11-18 16:43:52

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

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

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

There is no way to do this. I recommend separating the namespaces out into separate projects. Remember:

Separate namespaces, same project when logical separation makes sense.
Separate namespaces, separate projects when physical separation makes sense.

In this case, since you can't separate by namespace in nhibernate mappings, physical separation makes sense. You can, however, get around this with with fluent automaps that use a .Where or a ShouldMap configuration. Look up fluent automaps and see if that can get you where you want to be.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文