NHibernate 3.2に問題があります。nhibernate 3.2 thread_static問題
私は、Javaアプリケーションで使用したソリューションをC#4.0アプリケーションに移植します。 私たちが作成したいのは、NHibernate SessionFactoryを通じたセッションとトランザクションを処理する単純なメカニズムであり、トランザクションは作業単位の初心者によってインスタンス化され、次にすべてのpartecipantメソッドによって使用されます。より大きな作業単位の一部。しかし、これらのサブメソッドを直接呼び出すと、独自のトランザクションを処理します。
these question私はより良いアプローチを説明しました。 まずJavaの世界でやってみましたが、それはかなりうまく動作します。 私はNHibernate 3.2を使って、同じアプローチをc#4.0に移植しています。
すべての私のセッションとトランザクションを処理しようとしているクラスがOperationManager(あなたがUnitOfWorkManagerに考えること)colledされています。私がする必要がある時はいつでもここで
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();
}
}
ですDBにアクセスするには、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;
}
}
}
をベースクラスに私はこの問題は、私は<property name="current_session_context_class">thread_static</property>
を使用してスレッドごとのモデルで動作するようにNHibernateのセッションファクトリを構成した場合でも、ということである
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);
}
}
}
を持っている: 例がここに発見されましたOperationManager.beginOperation()への2回の呼び出しは、異なるセッションeを返すため、異なるトランザクションで返されます。
なぜこれが起こっているのか誰に教えてもらえますか?
編集は: フレディ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でコンテキストセッションを使用する方法の例をご覧ください:http://stackoverflow.com/questions/7454589/no-session-bound-to-the-current-context/7458905#7458905 –