NHibernate会话工厂计数限制?

时间:2017-10-25 16:53:12

标签: c# nhibernate

我通过代码创建多个会话工厂(不是配置文件) 我遇到的问题是在第20次工厂创建之后,我开始得到一个异常(MappingException),我不知道为什么。

无论顺序如何,20日后都会变坏。只要会话在前20个会话中,就会成功创建会话。

MappingException消息:唯一后缀100_ length必须小于最多4个字符

感谢任何帮助。

public static void AddPortfolioToConnectionstrings(string portfolio, string 
connectionString)
    {
        var configuration = new Configuration()
            .Configure()
            .SessionFactoryName(portfolio)
            .SetProperty("connection.connection_string", connectionString);

        ...

        _portfolios.Add(portfolio, configuration.BuildSessionFactory());
    }

1 个答案:

答案 0 :(得分:3)

像往常一样,NHibernate的错误消息并没有帮助任何人。

就我而言,我遇到了这个错误:

  

MappingException消息:唯一后缀100_的长度必须小于最大4个字符

经过深入研究,导致此错误的原因是连接字符串的服务器地址错误,然后提供了错误的凭据。


关于您的问题:连接20个目标数据库是不寻常的,但是可以做到。在下面向我展示的实现中,我使用了12个会话工厂,但是请确保您在64位进程空间中运行代码,否则它将很快耗尽32位进程可用的内存。

唯一需要注意的是,您需要具有一个自定义的Session工厂构建器,并将其绑定为单例。我的实现的轻量级版本如下:

public interface ISessionFactoryBuilder
{
    IDictionary<string, ISessionFactory> SessionFactories { get; }
}

public IDictionary<string, ISessionFactory> SessionFactories { get; private set; }
    private readonly IConfigurationManager _configurationManager;

    public SessionFactoryBuilder(IConfigurationManager configurationManager)
    {
        this._configurationManager = configurationManager;

        this.SessionFactories = this.BuildSessionFactories();
    }

    private IDictionary<string, ISessionFactory> BuildSessionFactories()
    {
        var sessionFactories = new Dictionary<string, ISessionFactory>(StringComparer.InvariantCultureIgnoreCase);
        var connectionStrings = this._configurationManager.GetConnectionStrings();

        if (connectionStrings.Count == 0)
            throw new ConfigurationErrorsException("No connection descriptions can be found!");

        foreach (ConnectionStringSettings item in connectionStrings)
            if (item.Name != "LocalSqlServer" && item.Name != "OraAspNetConString")
                sessionFactories.Add(item.Name, this.InitializeSessionFactory(item.ConnectionString, item.ProviderName));

        return sessionFactories;
    }

    private class Connectiontypes
    {
        public string Db_type { get; set; }
        public FluentConfiguration Configuration { get; set; }
    }

    private ISessionFactory InitializeSessionFactory(string connectionString = "", string providerName = "")
    {
        Trace.WriteLine($"{connectionString}");

        List<SessionFactoryBuilder.Connectiontypes> conntypes = new List<SessionFactoryBuilder.Connectiontypes> {
            new SessionFactoryBuilder.Connectiontypes
            {
                Db_type = "System.Data.SqlClient",
                Configuration = Fluently.Configure().Database(MsSqlConfiguration.MsSql2005.ConnectionString(connectionString).ShowSql() 
                    .Dialect<XMsSql2005Dialect>()) },
            new SessionFactoryBuilder.Connectiontypes
            {
                Db_type = "System.Data.OracleDataClient",
                Configuration = Fluently.Configure().Database(OracleDataClientConfiguration.Oracle10
                    .ConnectionString(connectionString).Provider<NHibernate.Connection.DriverConnectionProvider>()
                    .Driver<NHibernate.Driver.OracleManagedDataClientDriver>()
                    .Dialect<XOracle10gDialect>().ShowSql())
            },
            new SessionFactoryBuilder.Connectiontypes
            {
                Db_type = "System.Data.MySQLDataClient", Configuration = Fluently.Configure()
                    .Database(MySQLConfiguration.Standard.ConnectionString(connectionString).ShowSql())
            }
        };

        FluentConfiguration fluentConfiguration = conntypes.Find(x => x.Db_type == providerName).Configuration;

        fluentConfiguration.ExposeConfiguration(x =>
        {
            x.SetProperty("command_timeout", "120");
        });

#if DEBUG
        fluentConfiguration.ExposeConfiguration(x =>
        {
            x.SetInterceptor(new SqlStatementInterceptor());
        });
#endif

        var mappings = fluentConfiguration.Mappings(m =>
        {
            m.FluentMappings.AddFromAssemblyOf<UsersMap>();
        });

        var config = mappings.BuildConfiguration();

        foreach (PersistentClass persistentClass in config.ClassMappings)
        {
            persistentClass.DynamicUpdate = true;
        }

        var sessionFactory = mappings
#if DEBUG
            .Diagnostics(d => d.Enable(true))
            .Diagnostics(d => d.OutputToConsole())
#endif
            .BuildSessionFactory();

        return sessionFactory;
    }

    public void Dispose()
    {
        if (this.SessionFactories.Count > 0)
        {
            foreach (var item in this.SessionFactories)
            {

                item.Value.Close();
                item.Value.Dispose();
            }

            this.SessionFactories = null;
        }
    }
}

然后我将其与NInject绑定为:

Bind<ISessionFactoryBuilder>().To<SessionFactoryBuilder>().InSingletonScope().WithConstructorArgument("configurationManager", context => context.Kernel.Get<IConfigurationManager>());

当然,您必须在程序启动附近或我们称为Composition Root的任何地方执行此操作。

这里唯一缺少的是IConfigurationManager的明显实现,它只是我对ConfigurationManager的自定义包装,并传递给SessionFactoryBuilder的构造函数。

这样,您可以在应用程序启动时构建会话工厂构建器,而无需再次构建(显然要等到appdomain重新启动之后),因此,不会因为有那么多SessionFactories闲逛而获取内存泄漏或OutOfMemory异常已创建。