Я записал класс NHibernateSessionFactory, который содержит статический Nhibernate ISessionFactory. Это используется, чтобы удостовериться, что у нас только есть одна фабрика сессии, и в первый раз, когда OpenSession () называют, я создаю actuall 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, но я не уверен в том, что сделать. У кого-либо была та же проблема прежде? Каково лучшее решение?
sessionFactory
должен быть потокобезопасным синглтоном.
Общим шаблоном в Java является создание sessionFactory
в статическом инициализаторе. See HibernateUtil. То же самое можно сделать и в C#.
Существуют и другие паттерны для реализации singleton, включая использование блокировки или синхронизированных секций. Вот небольшой вариант, который должен решить вашу проблему, если я правильно понял.
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();
}
Я решил это с использованием 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);
}
}
Кажется, работает чудо. Но следует ли мне использовать вместо этого блокировку?