StructureMap,NHibernate和多个数据库 [英] StructureMap, NHibernate and multiple databases

查看:318
本文介绍了StructureMap,NHibernate和多个数据库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用流利的NHibernate的一个Asp.Net MVC 3应用程序。我只是试图添加使用StructureMap IoC容器。

I'm working on an Asp.Net MVC 3 application using Fluent NHibernate. I'm just attempting to add an IoC container using StructureMap.

我实现了自定义控制器工厂,使用StructureMap创建控制器并注入的依赖关系。每个控制器构造函数有一个或多个服务,进而采取DAO的构造函数的参数。每个DAO构造函数采用ISessionFactory。

I have implemented a custom controller factory which uses StructureMap to create the controller and inject dependencies. Each controller constructor takes one or more services, which in turn take a DAO as constructor argument. Each DAO constructor takes an ISessionFactory.

有关我的StructureMap NHibernate的注册表我有以下几点:

For my StructureMap NHibernate registry I have the following:

internal class NHibernateRegistry : Registry
{
    public NHibernateRegistry()
    {
        var connectionString = ConfigurationManager.ConnectionStrings["AppDb"].ConnectionString;

        For<ISessionFactory>()
                .Singleton()
                .Use(x => new AppSessionFactory().GetSessionFactory(connectionString));

        For<ISession>()
            .HybridHttpOrThreadLocalScoped()
            .Use(x => x.GetInstance<ISessionFactory>().OpenSession());
    }

}

public class AppSessionFactory
{
    public ISessionFactory GetSessionFactory(string connectionString)
    {
        return GetConfig(connectionString)
                .BuildSessionFactory();
    }

    public static FluentConfiguration GetConfig(string connectionString)
    {
        return Fluently.Configure()
            .Database(MsSqlConfiguration.MsSql2005.ConnectionString(x => x.Is(connectionString)))
            .Mappings(
                x => x.FluentMappings.AddFromAssemblyOf<AppEntity>());
    }
}

这一切工作正常单个数据库和单个会话工厂。然而,应用程序使用多个数据库。

This all works fine for a single database and single session factory. However the application uses multiple databases.

什么是处理这个问题的最佳方式?

What is the best way to handle this?

推荐答案

注册多个会话工厂很容易 - 问题是选择合适的人,当你需要它。举例来说,假设我们有某种有多个数据库实验室。每个实验室都有该位置一个位置和多个样品。我们可以有一个SampleRepository该模型。每个位置都有一个唯一的密钥,以确定它(例如,的LabX,LabY,黑色高地)。我们可以使用唯一键作为app.config文件的数据库连接字符串的名称。在这个例子中,我们将在app.config文件三种连接字符串。下面是一个示例connectionStrings节:

Registering multiple session factories is easy - the problem is selecting the right one when you need it. For example, let's say we have some sort of laboratory that has multiple databases. Each lab has a Location and multiple Samples for that location. We could have a SampleRepository that models that. Each Location has a unique key to identify it (e.g. "LabX", "LabY", "BlackMesa"). We can use that unique key as the name of the database connection string in the app.config file. In this example, we would have three connection strings in the app.config file. Here's a sample connectionStrings section:

<connectionStrings>
  <add name="LabX" connectionString="Data Source=labx;User ID=someuser;Password=somepassword"/>
  <add name="LabY" connectionString="Data Source=laby;User ID=someuser;Password=somepassword"/>
  <add name="BlackMesa" connectionString="Data Source=blackmesa;User ID=freemang;Password=crowbar"/>
</connectionStrings>

因此​​,我们需要为每个连接字符串一个唯一的会话工厂。让我们创建一个包装ISessionFactory一个NamedSessionFactory:

Thus, we need to have a unique session factory for each connection string. Let's create a NamedSessionFactory that wraps ISessionFactory:

public interface INamedSessionFactory
{
    public string Name { get; } // The name from the config file (e.g. "BlackMesa")
    public ISessionFactory SessionFactory { get; }
}

public class NamedSessionFactory : INamedSessionFactory
{
    public string Name { get; private set; }
    public ISessionFactory SessionFactory { get; private set; }

    public NamedSessionFactory(string name, ISessionFactory sessionFactory)
    {
        Name = name;
        SessionFactory = sessionFactory;
    }
}

现在,我们需要修改AppSessionFactory一点。首先,你所创建的是一个session工厂的工厂 - 这并不完全是我们要寻找的。我们希望给我们的工厂的位置,并得到一个会话出来的,而不是一个会话工厂。功能NHibernate是什么给我们会议的工厂。

Now we need to modify your AppSessionFactory a bit. First off, what you've created is a session factory factory - that's not quite what we're looking for. We want to give our factory a location and get a session out of it, not a session factory. Fluent NHibernate is what gives us session factories.

public interface IAppSessionFactory
{
    ISession GetSessionForLocation(string locationKey);
}

这里的窍门是接受的构造INamedSessionFactory对象的列表。 StructureMap应该给我们所有,我们已经注册的INamedSessionFactory对象。我们会登记在第二。

The trick here is accept a list of INamedSessionFactory objects in the constructor. StructureMap should give us all of the INamedSessionFactory objects that we've registered. We'll get to registration in a second.

public class AppSessionFactory : IAppSessionFactory
{
    private readonly IList<INamedSessionFactory> _factories;

    public AppSessionFactory(IEnumerable<INamedSessionFactory factories)
    {
        _factories = new List<INamedSessionFactory>(factories);
    }

这是那里的奇迹发生。给定一个位置关键,我们通过我们的工厂寻找一个具有相同的名称locationKey列表运行,那么要求它打开一个会话,并返回给调用者。

This is where the magic happens. Given a location key, we run through our list of factories looking for one with the same name as locationKey, then ask it to open a session and return it to the caller.

    public ISession GetSessionForLocation(string locationKey)
    {
        var sessionFactory = _factories.Where(x => x.Name == locationKey).Single();

        return sessionFactory.OpenSession();
    }
}

现在,让我们线这一切都在一起。

Now let's wire this all together.

internal class NHibernateRegistry : Registry
{
    public NHibernateRegistry()
    {

我们将遍历所有在我们的app.config文件中的连接字符串(会有三个人在这个例子中),并为每一个注册一个INamedSessionFactory对象。

We're going to loop through all of the connection strings in our app.config file (there would be three of them in this example) and register an INamedSessionFactory object for each one.

        foreach (ConnectionStringSettings location in ConfigurationManager.ConnectionStrings)
        {
            For<INamedSessionFactory>()
                .Singleton()
                .Use(x => new NamedSessionFactory(
                    location.Name,
                    GetSessionFactory(location.ConnectionString));
        }

我们还需要注册IAppSessionFactory。

We also need to register IAppSessionFactory.

        For<IAppSessionFactory>()
          .Singleton()
          .Use<AppSessionFactory>();
    }

您会注意到我们搬到这个逻辑出了工厂类的......这些都是从流利的NHibernate创建会话工厂helper方法。

You'll notice that we've moved this logic out of the factory class... These are helper methods for creating session factories from Fluent NHibernate.

    private static ISessionFactory GetSessionFactory(string connectionString)
    {
        return GetConfig(connectionString)
                .BuildSessionFactory();
    }

    public static FluentConfiguration GetConfig(string connectionString)
    {
        return Fluently.Configure()
            .Database(MsSqlConfiguration.MsSql2005.ConnectionString(x => x.Is(connectionString)))
            .Mappings(
                x => x.FluentMappings.AddFromAssemblyOf<AppEntity>());
    }
}

这应该这样做!让我们创建一个存储库在我们的样品得到...

That should do it! Let's create a repository for getting at our samples...

public class SampleRepository
{
    private readonly IAppSessionFactory _factory;

    public SampleRepository(IAppSessionFactory factory)
    {
        _factory = factory;
    }

    public IEnumerable<Sample> GetSamplesForLocation(Location location)
    {
        using (ISession session = _factory.GetSessionForLocation(location.Key)
        {
            foreach (Sample sample in session.Query<Sample>())
              yield return sample;
        }
    }
}

现在可以得到SampleRepository的单个实例,并使用GetSamplesForLocation方法从任何我们在app.config中注册的三个数据库的拉样品。可能要避免黑色高地虽然。我的理解有问题存在。

Now you can get a single instance of SampleRepository and use the GetSamplesForLocation method to pull samples from any of the three databases we have registered in app.config. Might want to avoid BlackMesa though. I understand there were problems there.

这篇关于StructureMap,NHibernate和多个数据库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆