Убедитесь, что NHibernate SessionFactory создается только один раз - PullRequest
14 голосов
/ 02 марта 2010

Я написал класс NHibernateSessionFactory, который содержит статический Nhibernate ISessionFactory. Это используется, чтобы убедиться, что у нас есть только одна фабрика сессий, и при первом вызове OpenSession () я создаю actall SessionFactory - в следующий раз я использую то же самое и открываю на нем сессию. Код выглядит так:

public class NhibernateSessionFactory : INhibernateSessionFactory
{
    private static ISessionFactory _sessionFactory;

    public ISession OpenSession()
    {
        if (_sessionFactory == null)
        {
            var cfg = Fluently.Configure().
                Database(SQLiteConfiguration.Standard.ShowSql().UsingFile("Foo.db")).
                Mappings(m => m.FluentMappings.AddFromAssemblyOf<MappingsPersistenceModel>());
            _sessionFactory = cfg.BuildSessionFactory();
            BuildSchema(cfg);
        }
        return _sessionFactory.OpenSession();
    }

    private static void BuildSchema(FluentConfiguration configuration)
    {
        var sessionSource = new SessionSource(configuration);
        var session = sessionSource.CreateSession();
        sessionSource.BuildSchema(session);            
    }
}

Теперь у меня проблема. Мое приложение разделено между клиентом и сервером. Материал Nhibernate находится на стороне сервера. При запуске и мой клиент, и сервер хотят получить доступ к базе данных через некоторые сервисы, которые будут использовать NhibernateSessionFactory. Результатом является условие состязания с тем, создается ли _sessionFactory до того, как запрос поступит от клиента. Если это не так, то не получится ..

Полагаю, мне нужен механизм очередей или ожидания в NhibernateSessionFactory, но я не уверен, что делать. У кого-нибудь была такая же проблема раньше? Какое лучшее решение?

Ответы [ 2 ]

19 голосов
/ 02 марта 2010

sessionFactory должен быть потокобезопасным синглтоном.

Распространенный шаблон в Java - это создание sessionFactory в статическом инициализаторе. См. HibernateUtil . Вы можете сделать то же самое в C #.

Существуют и другие шаблоны для реализации синглтона, включая использование блокировок или синхронизированных секций Вот небольшой вариант, который должен решить вашу проблему, если я правильно понял.

static readonly object factorylock = new object();

public ISession OpenSession()
{
    lock (factorylock)
    {
       if (_sessionFactory == null)
       {
            var cfg = Fluently.Configure().
               Database(SQLiteConfiguration.Standard.ShowSql().UsingFile("Foo.db")).
               Mappings(m => m.FluentMappings.AddFromAssemblyOf<MappingsPersistenceModel>());
            _sessionFactory = cfg.BuildSessionFactory();
            BuildSchema(cfg);
        }
    }
    return _sessionFactory.OpenSession();
}
4 голосов
/ 02 марта 2010

Я решил это с помощью Mutex при создании SessionFactory. Это выглядит разумно:

public class NhibernateSessionFactory : INhibernateSessionFactory
{
    private static ISessionFactory _sessionFactory;
    private static Mutex _mutex = new Mutex();  // <-- Added

    public ISession OpenSession()
    {
        if (_sessionFactory == null)
        {
            _mutex.WaitOne();              // <-- Added
            if (_sessionFactory == null)   // <-- Added
            {                              // <-- Added
                var cfg = Fluently.Configure().
                    Database(SQLiteConfiguration.Standard.ShowSql().UsingFile("Foo.db")).
                    Mappings(m => m.FluentMappings.AddFromAssemblyOf<MappingsPersistenceModel>());
                _sessionFactory = cfg.BuildSessionFactory();
                BuildSchema(cfg);
            }                              // <-- Added
            _mutex.ReleaseMutex();         // <-- Added

        }
        return _sessionFactory.OpenSession();
    }

    private static void BuildSchema(FluentConfiguration configuration)
    {
        var sessionSource = new SessionSource(configuration);
        var session = sessionSource.CreateSession();
        sessionSource.BuildSchema(session);            
    }
}

Кажется, работает как шарм. Но я должен использовать блокировку вместо этого?

...