У меня проблема с NHibernate 3.2.
Я портирую решение, которое мы использовали в приложении Java, на приложение ac # 4.0.Мы хотим создать простой механизм, который обрабатывает сеанс и транзакцию через NHibernate SessionFactory, позволяя инициализировать транзакцию начинающему элементу работы, а затем использоваться всем методом partecipant, даже не зная, что они являются частьюбольшей единицы работы.Но если вы будете вызывать эти вспомогательные методы напрямую, они будут обрабатывать свои собственные транзакции.
В эти вопросы Я лучше объяснил наш подход.Мы впервые сделали это в мире Java, и он работает довольно хорошо.Теперь я переношу тот же подход на c # 4.0, используя NHibernate 3.2.
Класс, который будет обрабатывать все мои сеансы и транзакции, называется OperationManager (вы можете подумать об UnitOfWorkManager):
public class OperationManager : IDisposable
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
ITransaction tx = null;
ISession session = null;
bool isInternalTransaction = false;
public ISession BeginOperation()
{
logger.Debug("Thread : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
session = PersistenceManager.Istance.GetSession();
if (session.Transaction.IsActive)
{
isInternalTransaction = false;
tx = session.Transaction;
logger.Debug(GetCallerClassDotMethod() + " is binding to transaction " + tx.GetHashCode());
}
else
{
isInternalTransaction = true;
tx = session.Transaction;
tx.Begin();
logger.Debug("Transaction " + tx.GetHashCode() + " created by " + GetCallerClassDotMethod());
}
logger.Debug("Session hash " + session.GetHashCode());
return session;
}
private String GetCallerClassDotMethod() {
// needed to get the Business Logic method calling the public methods
var st = new StackTrace();
var sf = st.GetFrame(2);
var methodReference = sf.GetMethod().Name;
var classReference = sf.GetMethod().DeclaringType.FullName;
return string.Concat(classReference, ".", methodReference);
}
public void CommitOperation()
{
if (isInternalTransaction)
{
tx.Commit();
logger.Debug(GetCallerClassDotMethod() + " is committing transaction " + tx.GetHashCode());
}
}
public void RollbackOperation()
{
if (isInternalTransaction)
{
tx.Rollback();
logger.Debug(GetCallerClassDotMethod() + " is rolling back transaction " + tx.GetHashCode());
}
}
public void Dispose()
{
tx.Dispose();
session.Dispose();
}
}
Вот мой PersistenceManager
internal class PersistenceManager : IDisposable
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private static PersistenceManager _istance;
private ISessionFactory _SessionFactory;
private static Object _lock = new Object();
public static PersistenceManager Istance
{
get
{
lock (_lock)
{
if (_istance == null)
{
_istance = new PersistenceManager();
logger.Info("New PersistenceManager instance created");
}
return _istance;
}
}
}
private PersistenceManager()
{
// Initialize
Configuration cfg = new Configuration();
cfg.Configure(ConfigurationManager.ConfigurationManager.Istance.hibernateConfiguration);
cfg.SetProperty("connection.connection_string", ConfigurationManager.ConfigurationManager.Istance.connectionString);
/* Note: The AddAssembly() method requires that mappings be
* contained in hbm.xml files whose BuildAction properties
* are set to ‘Embedded Resource’. */
// Add class mappings to configuration object
System.Reflection.Assembly thisAssembly = typeof(PersistenceManager).Assembly;
cfg.AddAssembly(thisAssembly);
// Create session factory from configuration object
_SessionFactory = cfg.BuildSessionFactory();
}
public void Dispose()
{
_SessionFactory.Dispose();
}
/// <summary>
/// Close this Persistence Manager and release all resources (connection pools, etc). It is the responsibility of the application to ensure that there are no open Sessions before calling Close().
/// </summary>
public void Close()
{
_SessionFactory.Close();
}
public ISession GetSession()
{
return _SessionFactory.OpenSession();
}
}
Теперь, когда мне нужно получить доступ к БД, я использую экземпляр OperationManager, чтобы получить текущий сеанс (и текущую транзакцию) и использовать его для всех своих нужд.Пример можно найти здесь:
public IList<Agency> getAllAgencies()
{
using (var om = new OperationManager())
{
try
{
om.BeginOperation();
var result = base.Load<Agency>().ToList();
om.CommitOperation();
return result;
}
catch (Exception ex)
{
om.RollbackOperation();
throw ex;
}
}
}
и в базовом классе у меня есть
protected IQueryable<T> Load<T>() where T : Model.ModelEntity
{
using (var om = new OperationManager())
{
try
{
var session = om.BeginOperation();
var entities = session.Query<T>();
om.CommitOperation();
return entities;
}
catch (Exception ex)
{
om.RollbackOperation();
throw new Exception(msg, ex);
}
}
}
Проблема заключается в том, что даже если я настроил фабрику сеансов NHibernate для работы с каждым потокомВ модели, использующей <property name="current_session_context_class">thread_static</property>
, два вызова OperationManager.beginOperation () возвращают сеанс разницы, то есть с другой транзакцией.
Кто-нибудь может сказать мне, почему это происходит?
Отредактировано: Следуя предложению Фреди Требу, я попытался реализовать механизм, который создает новый сеанс или просто получает текущий, используя статический объект CurrentSessionContext из NHibernate.Жаль, это все еще не работает.После очистки кода, избегая всего, что связано с транзакциями, сессиями, единицами работы и т. Д., Я написал очень тривиальный класс и понял, что использование
<property name="current_session_context_class">thread_static</property>
приносит мне проблемы с sqlсервер 2008 дб.Используя этот класс контекста, используя классический подход SessionFactory.OpenSession () и затем загружая некоторые данные, я получаю следующую ошибку:
System.Data.SqlClient.SqlException: A transport-level error has occurred when receiving results from the server. (provider: Shared Memory Provider, error: 0 - Invalid Handle.)
Есть идеи, почему это произошло?