Как добавить сопоставления по пространству имен в Fluent NHibernate

В моем приложении мне нужно поговорить с несколькими базами данных. Я справляюсь с этим в NHibernate, создавая одну SessionFactory для каждой базы данных (я предполагаю, что это правильное решение). Итак, у меня есть два набора моделей (по одному для каждой базы данных) и два набора сопоставлений Fluent NHibernate ClassMap<>. Оба находятся в одном проекте (разделены пространством имен), и я хотел бы сохранить его в таком виде.

Проблема возникает при создании SessionFactory. Насколько я понимаю, в Fluent NHibernate есть два основных метода добавления сопоставлений:

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

Если я использую первую перегрузку, то мои фабрики сеансов получат все сопоставления для обеих баз данных. Если я использую второй, я должен указать каждую отдельную ClassMap. Я хочу что-нибудь вроде FluentMappings.AddFromNamespace(). Есть ли способ сделать это?


person Gabe Moothart    schedule 01.06.2011    source источник


Ответы (4)


Странно, что 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"));
person Daniel Schilling    schedule 01.06.2011
comment
+1 Я обнаружил нечто подобное, но это более общий подход. - person Gabe Moothart; 02.06.2011
comment
Это не отображает SubClassMaps, поскольку они не могут быть назначены из IMappingProvider. stackoverflow.com/a/6207141/206297 содержит расширенный список MappingProvider, которые следует проверить. - person ngm; 15.06.2015

Я закончил писать метод расширения, который делает это за меня. В основном он использует отражение, чтобы перебирать все интересующие меня типы и добавлять их один за другим. Он основан на реализации 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 будут добавлены или удалены некоторые сопоставляемые интерфейсы, они не будут включены.

Но для моих целей это работает.

person Gabe Moothart    schedule 01.06.2011
comment
Это именно то, что мне было нужно - спасибо! Это должно быть просто встроено в FNH. - person Daniel Williams; 08.02.2013

Нет возможности сделать это. Я рекомендую разделить пространства имен на отдельные проекты. Помните:

Отдельные пространства имен, один и тот же проект, когда логическое разделение имеет смысл. Отдельные пространства имен, отдельные проекты, когда имеет смысл физическое разделение.

В этом случае, поскольку вы не можете разделить пространство имен в сопоставлениях nhibernate, физическое разделение имеет смысл. Однако вы можете обойти это с помощью свободных автокарт, которые используют конфигурацию .Where или ShouldMap. Поищите беглые автоматы и посмотрите, сможет ли это привести вас туда, где вы хотите быть.

person Fourth    schedule 01.06.2011

person    schedule
comment
Я не использую автоматические приложения, я явно указываю свои сопоставления с помощью сопоставлений ClassMap ‹›. - person Gabe Moothart; 02.06.2011