如何在FluentNhibernate AutoPersistenceModel生成器中使用来自许多程序集的映射覆盖

时间:2010-07-16 12:28:23

标签: fluent-nhibernate

是否可以配置自动存在模型以从多个程序集中读取映射和映射覆盖。

目前我使用

public AutoPersistenceModel Generate()
        {
            var model =
                new AutoPersistenceModel()
                    .AddEntityAssembly(Assembly.GetAssembly(typeof(User)))
                    .Where(
                    this.GetAutoMappingFilter).Conventions.Setup(this.GetConventions()).Setup(this.GetSetup()).

                    UseOverridesFromAssemblyOf<AutoPersistenceModelGenerator>();

            return model;
        }

        public AutoPersistenceModel Generate(params Assembly[] assemblies)
        {
            var model = this.Generate();
            assemblies.ToList().ForEach(x => model.AddEntityAssembly(x));

            return model;
        }

问题在于

  UseOverridesFromAssemblyOf<AutoPersistenceModelGenerator>();

只需一个程序集。 BUt我想从不同的程序集中收集映射和它们的其他内容。

由于

2 个答案:

答案 0 :(得分:2)

我们采用了一种略微不同的方法来解决这个问题,使用1.3.x版本的FNH,并考虑到一些特定的设计目标:

  • 保留我们的域名实体POCO。
  • 利用FNH自动持久性机制。
  • 将程序集中的IAutoMappingOverride实例与它们所依赖的实体打包在一起。
  • 允许包含映射实体的新程序集的“插件”,而不必更改核心FNH配置。

与OP的解决方案非常相似,我们所有的映射实体都从一组众所周知的基类继承。有了这个以及可以确实多次调用AutoPersistenceModel.UseOverridesFromAssembly()的事实,我们能够对我们的自动映射配置类进行简单的修改,以动态添加覆盖程序集:

internal sealed class SessionConfiguration : DefaultAutomappingConfiguration
{
    public AutoPersistenceModel PersistenceModel
    {
        get
        {
            Assembly[] assembliesToMap = MappedAssemblyResolver.GetMappedAssemblies();
            AutoPersistenceModel model = AutoMap.Assemblies(new SessionConfiguration(), assembliesToMap);

            foreach (Assembly potentiallyMapped in MappedAssemblyResolver.GetOverrideAssemblies(assembliesToMap))
            {
                model.UseOverridesFromAssembly(potentiallyMapped);
            }

            model.Conventions.AddFromAssemblyOf<SessionConfiguration>();
            // other FNH configuration options omitted

            return model;
        }
    }

    public override bool ShouldMap(Type type)
    {
        return type.IsSubclassOfRawGeneric(typeof(DomainObject<>));
    }
}

MappedAssemblyResolver看起来像这样:

internal static class MappedAssemblyResolver
{
    public static Assembly[] GetMappedAssemblies()
    {
        Assembly[] mappedAssemblies; 
        // TODO: implement your strategy for resolving assemblies

        return mappedAssemblies;
    }

    public static IEnumerable<Assembly> GetOverrideAssemblies(Assembly[] mappedAssemblies)
    {
        mappedAssemblies.CheckNull("mappedAssemblies");

        return mappedAssemblies;
    }
}

一些注意事项:

  1. DomainObject是我们的基本域实体。它包含常见的内容,如Id,DateCreated等。
  2. IsSubclassOfRawGeneric(Type)是一种扩展方法,可用here
  3. CheckNullOrEmpty(string)是一种扩展方法,可用here
  4. 您需要在GetMappedAssemblies()中实现一种实际解析程序集的方法。我们对AppDomain.CurrentDomain进行了一些检查,并应用了一些规则来确定我们认为匹配的程序集。
  5. 另请注意,虽然我们将IAutoMappingOverride实例放在与实体相同的程序集中,但如果您的目标是进一步将域与FNH分离,则可以轻松更改GetOverrideAssemblies(Assembly [])的实现。

    无论哪种方式,这应该允许您随意添加新的映射实体(或包含它们的新程序集)及其相关的映射覆盖,而不必过多考虑它们对底层FNH AutoPersistenceModel的添加。

答案 1 :(得分:1)

因此.UseOverridesFromAssemblyOf的问题是它们不会重复类型。

从FluentNHibernate剪下的代码:

public AutoPersistenceModel UseOverridesFromAssembly(Assembly assembly)
    {
      this.alterations.Add(new AutoMappingOverrideAlteration(assembly));
      return this;
    }
public AutoMappingAlterationCollection Add(IAutoMappingAlteration alteration)
    {
      if (!this.alterations.Exists(a => a.GetType() == alteration.GetType()))
      {
        this.alterations.Add(alteration);
      }
      return this;
    }

您可以看到不允许添加重复类型。

在调查FNH代码后,我发现他们最终改变了AutoMappingOverrideAlteration,我只是写了一个扩展来应用这个改变

 public static class AutoPersistenceModelExtension
    {
        public static AutoPersistenceModel AddMappingAssembly(this AutoPersistenceModel model, Assembly assembly)
        {
            new AutoMappingOverrideAlteration(assembly).Alter(model);
            return model;
        }

        public static AutoPersistenceModel AddMappingFromAssemblyOf<T>(this AutoPersistenceModel model)
        {
            return model.AddEntityAssembly(typeof (T).Assembly);
        }


    }

结果是: 我们的应用程序是基于组件构建的,每个组件为这些实体提供自己的实体和映射。每个组件都应该从BaseComponent类派生,该类具有改变模型的抽象方法。

Exof FulfillmentModuleRegistration:

public override void AddToModel(AutoPersistenceModel autoPersistenceModel)
        {
            autoPersistenceModel.AddEntityAssembly(typeof(SupplierListItem).Assembly);
            autoPersistenceModel.AddMappingFromAssemblyOf<SupplierListItemMappingOverride>();
        }

和我们的global.asax.cs:

 var autoPersistenceModel = new AutoPersistenceModelGenerator().Generate();
            //TODO: Refactor this, instead of instantiate each module we have to go thought a list of loaded module and apply their model alteration
            new QuestionBankModuleRegistration().AddToModel(autoPersistenceModel);
            new FulfilmentServiceAreaRegistration().AddToModel(autoPersistenceModel);

            var cfg = NHibernateSession.Init(
                this.webSessionStorage,
                new[] { this.Server.MapPath("~/bin/baseMappings.dll") },
                autoPersistenceModel,
                this.Server.MapPath("~/Hibernate.cfg.xml"));

baseMappings.dll包含我们的基本实体,例如:Users,Lookups等。因此它可以是包含基本,默认映射,约定等的任何程序集。