【发布时间】:2011-11-15 20:03:05
【问题描述】:
我遇到了 NHibernate 3.2 的问题。
我正在将我们在 Java 应用程序中使用的解决方案移植到 c# 4.0 应用程序。 我们想要创建一个简单的机制,通过 NHibernate SessionFactory 处理会话和事务,让工作单元初学者实例化事务,然后被所有参与者方法使用,甚至不知道它们是一部分更大的工作单元。但是如果你直接调用这些子方法,它们会自己处理事务。
在these question 中,我更好地解释了我们的方法。 我们首先在 Java 世界中做到了,它工作得很好。 现在我正在使用 NHibernate 3.2 将相同的方法移植到 c# 4.0。
将处理我所有会话和事务的类是 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);
}
}
}
问题在于,即使我使用 <property name="current_session_context_class">thread_static</property> 将 NHibernate 会话工厂配置为在每个线程模型上工作,对 OperationManager.beginOperation() 的两次调用都会返回不同的会话,因此具有不同的事务。
谁能告诉我为什么会这样?
已编辑: 按照 Fredy Treboux 的建议,我尝试使用 NHibernate 的 CurrentSessionContext 静态对象来实现一种创建新会话或仅获取当前会话的机制。 太糟糕了,这仍然不起作用。 清理代码后,避免与事务、会话、工作单元等相关的所有内容,我编写了一个非常简单的类,我发现使用
<property name="current_session_context_class">thread_static</property>
给我一个关于 sql server 2008 db 的问题。 在经典的 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.)
知道为什么会这样吗?
【问题讨论】:
-
查看此示例,了解如何在 NH 中使用上下文会话:stackoverflow.com/questions/7454589/…
标签: c# nhibernate design-patterns