Web 開発に NHibernate を使用しているほとんどの友人は、Session-Per-Request モードを知っていますが、インターネット上にはその正しい使用方法の例があまりありません。インターネット上の多くの記事が同じ間違いを犯しています。そしてこの間違いは広まっています...
まずは庭の Flyear による記事「NHibernate One Session Per Request Simple Implementation」を見てみましょう。
最初に NHibernate を設定しても問題はありません。
<property name='current_session_context_class'>ウェブ</property>
エラーは NHinbernateSessionFactory クラスにあります (クラス名はすべて間違っています)。NHinbernateSessionFactory.GetCurrentSession には HttpContext の操作が含まれていません。実際には、クラス名は NHibernateHelper に変更されています。
パブリック シールド クラス NHibernateHelper
{
public static readonly ISessionFactory SessionFactory;
staticNHibernateHelper()
{
SessionFactory = 新しい構成()
.Configure()
.AddAssembly(/**/)
.BuildSessionFactory();
}
パブリック静的 ISession GetCurrentSession()
{
戻りSessionFactory.GetCurrentSession();
}
}
current_session_context_class を Web として構成すると、NHibernate は初期化中に NHibernate.Context.WebSessionContext クラスのインスタンスを生成します。 WebSessionContext クラスのソース コードは次のとおりです。
【シリアライズ可能】
パブリック クラス WebSessionContext : MapBasedSessionContext
{
//フィールド
private const string SessionFactoryMapKey = "NHibernate.Context.WebSessionContext.SessionFactoryMapKey";
// メソッド
public WebSessionContext(ISessionFactoryImplementor ファクトリ) : ベース(ファクトリ)
{ }
保護されたオーバーライド IDictionary GetMap()
{
return (HttpContext.Current.Items[SessionFactoryMapKey] を IDictionary として);
}
protected オーバーライド void SetMap(IDictionary value)
{
HttpContext.Current.Items[SessionFactoryMapKey] = 値;
}
}
WebSessionContext は、HttpContext をカプセル化する Session-Per-Request モードを実装しているため、補助クラス (NHibernateSessionFactory または NHibernateHelper) で HttpContext を操作する必要はありません。
WebSessionContext のインスタンスからセッションを取得するだけです。 WebSessionContext は ICurrentSessionContext インターフェイスを実装しているため、WebSessionContext クラスから現在の ISession を取得するのは非常に簡単です。
パブリック インターフェイス ICurrentSessionContext
{
ISession CurrentSession();
}
NHibernate.Context 名前空間のクラスとインターフェイス
(注: current_session_context_class は、それぞれ ManagedWebSessionContext、CallSessionContext、および ThreadStaticSessionContext クラスに対応する、Managed_web、Call、thread_static として構成することもできます)
実際の使用では、WebSessionContext の CurrentSession() メソッドを直接呼び出す必要はありません。これは、ISessionFactory が 1 ステップでセッションを取得できる簡単なメソッドを提供しているためです。
パブリック インターフェイス ISessionFactory : IDisposable
{
ISession GetCurrentSession();
//……
}
ISessionFactory.GetCurrentSession メソッドの具体的な実装について説明します。
Configuration.BuildSessionFactory メソッドは、実際には SessionFactoryImpl クラスのインスタンスを返します。SessionFactoryImpl のコードの一部を簡単に見てみましょう。
1 つのパブリック シールド クラス SessionFactoryImpl
2: ISessionFactoryImplementor、IMapping、ISessionFactory、IDisposable、IObjectReference
3 {
4 プライベート読み取り専用 ICurrentSessionContext currentSessionContext;
5
6 パブリック ISession GetCurrentSession()
7 {
8 if (this.currentSessionContext == null)
9 {
10 新しい HibernateException(
11 "CurrentSessionContext が構成されていません (プロパティ current_session_context_class を設定します)!");
12}
13 return this.currentSessionContext.CurrentSession();
14}
15
16 パブリック ICurrentSessionContext CurrentSessionContext
17 {
18 get { return this.currentSessionContext }
19}
20
21 プライベート ICurrentSessionContext BuildCurrentSessionContext()
22 {
23 文字列名 = PropertiesHelper.GetString("current_session_context_class", this.properties, null);
24 文字列 str2 = 名前;
25 if (str2 != null)
26 {
27 if (str2 == "call") return new CallSessionContext(this);
28 if (str2 == "thread_static") return new ThreadStaticSessionContext(this);
29 if (str2 == "web") return new WebSessionContext(this);
30 if (str2 == "managed_web") は新しい ManagedWebSessionContext(this) を返します。
31}
32 その他
33 null を返します。
34 トライ
35 {
36 タイプ type = ReflectHelper.ClassForName(name);
37 戻り値 (ICurrentSessionContext)Environment.BytecodeProvider.ObjectsFactory
38.CreateInstance(type, new object[] { this });
39 }
40 catch (例外例外)
41 {
42 log.Error("現在のセッション コンテキスト [" + 名前 + "]" を構築できません。例外);
43 null を返します。
44}
45 }
46 //……
47 }
SessionFactoryImpl がインスタンス化されると、BuildCurrentSessionContext() メソッド (21 行目) が呼び出され、currentSessionContext フィールドに値が割り当てられます。特定の値は、構成ファイル内の current_session_context_class によって決まります。
ISessionFactory の GetCurrentSession() は、ICurrentSessionContext の CurrentSession() メソッドを呼び出します (6 行目)。
上記のコードは非常に単純なので、誰もがすでに理解しているはずです。
記事「NHibernate One Session Per Request Simple Implementation」には不適切な箇所が 2 か所あります。
1. すべてのリクエストがデータベースにアクセスするためにセッションを必要とするわけではありません。この記事の Global.asax のコードは、すべてのリクエストの開始時に WebSessionContext.Bind() を実行します。これにより、多くのセッションが無駄になりますが、NHibernate のセッションは軽量ですが、より合理的なアプローチは、「本当に必要な」時間バインディングです。
2. WebSessionContext.Unbind メソッドには ISessionFactory インターフェイスのインスタンスが必要なため、SessionFactory を公開するにはヘルパー クラス (NHibernateSessionFactory または NHibernateHelper) を使用する必要があります。
最初の質問は解決しやすいため、全員とコミュニケーションをとるために返信に残してください。
2番目の質問については次のエッセイで答えます。
私は長い間 NHibernate を学習していない初心者なので、間違いがある場合は修正してください。