Kebanyakan teman-teman yang menggunakan NHibernate untuk pengembangan web mengetahui mode Session-Per-Request, namun tidak banyak contoh cara menggunakannya dengan benar di Internet. Banyak artikel di Internet, termasuk di taman, yang melakukan kesalahan yang sama. dan kesalahan ini telah menyebar...
Pertama-tama mari kita lihat artikel oleh Flyear di taman, "Implementasi Sederhana NHibernate Satu Sesi Per Permintaan".
Tidak ada salahnya mengkonfigurasi NHibernate terlebih dahulu:
<nama properti='current_session_context_class'>web</properti>
Kesalahannya ada di kelas NHinbernateSessionFactory (semua nama kelas salah). NHinbernateSessionFactory.GetCurrentSession tidak boleh menyertakan operasi di HttpContext. GetCurrentSession sebenarnya sangat sederhana.
kelas NHibernateHelper yang disegel publik
{
ISessionFactory SessionFactory yang hanya dapat dibaca statis publik;
statisNHibernateHelper()
{
SessionFactory = Konfigurasi baru()
.Konfigurasi()
.AddAssembly(/**/)
.BuildSessionFactory();
}
ISession statis publik GetCurrentSession()
{
kembali SessionFactory.GetCurrentSession();
}
}
Konfigurasikan current_session_context_class sebagai web, dan NHibernate akan menghasilkan instance kelas NHibernate.Context.WebSessionContext selama inisialisasi. Kode sumber kelas WebSessionContext adalah sebagai berikut:
[Dapat diserialkan]
WebSessionContext kelas publik : MapBasedSessionContext
{
//Bidang
string const pribadi SessionFactoryMapKey = "NHibernate.Context.WebSessionContext.SessionFactoryMapKey";
// Metode
WebSessionContext publik (pabrik ISessionFactoryImplementor): basis (pabrik)
{ }
penggantian yang dilindungi IDictionary GetMap()
{
return (HttpContext.Current.Items[SessionFactoryMapKey] sebagai IDictionary);
}
penggantian yang dilindungi batal SetMap (nilai IDictionary)
{
HttpContext.Current.Items[SessionFactoryMapKey] = nilai;
}
}
WebSessionContext mengimplementasikan mode Session-Per-Request, yang merangkum HttpContext, jadi kita tidak perlu mengoperasikan HttpContext di kelas tambahan kita (NHibernateSessionFactory atau NHibernateHelper).
Kita hanya perlu mendapatkan Sesi dari instance WebSessionContext. Mendapatkan ISession saat ini dari kelas WebSessionContext cukup sederhana, karena WebSessionContext mengimplementasikan antarmuka ICurrentSessionContext:
antarmuka publik ICurrentSessionContext
{
ISession CurrentSession();
}
Kelas dan antarmuka di namespace NHibernate.Context
(Catatan: current_session_context_class juga dapat dikonfigurasi sebagai Managed_web, Call, thread_static, sesuai dengan masing-masing kelas ManagedWebSessionContext, CallSessionContext, dan ThreadStaticSessionContext)
Dalam penggunaan sebenarnya, kita tidak perlu memanggil metode CurrentSession() WebSessionContext secara langsung, karena ISessionFactory menyediakan metode sederhana yang memungkinkan kita memperoleh Sesi dalam satu langkah:
antarmuka publik ISessionFactory : IDisposable
{
ISession GetCurrentSession();
//......
}
Mari kita bahas implementasi spesifik metode ISessionFactory.GetCurrentSession:
Metode Configuration.BuildSessionFactory sebenarnya mengembalikan instance kelas SessionFactoryImpl. Mari kita lihat sekilas beberapa kode SessionFactoryImpl:
1 kelas SessionFactoryImpl yang disegel publik
2: ISessionFactoryImplementor, IMapping, ISessionFactory, IDisposable, IObjectReference
3 {
4 ICurrentSessionContext hanya baca pribadi currentSessionContext;
5
6 ISession publik GetCurrentSession()
7 {
8 jika (ini.currentSessionContext == null)
9 {
10 lempar HibernateException baru(
11 "Tidak ada CurrentSessionContext yang dikonfigurasi (setel properti current_session_context_class)!");
12}
13 kembalikan this.currentSessionContext.CurrentSession();
14}
15
16 ICurrentSessionContext publik Konteks Sesi Saat Ini
17 {
18 dapatkan { kembalikan ini.currentSessionContext }
19}
20
21 ICurrentSessionContext BuildCurrentSessionContext() pribadi
dua puluh dua {
23 string nama = PropertiesHelper.GetString("current_session_context_class", this.properties, null);
24 senar str2 = nama;
25 jika (str2 != nol)
26 {
27 if (str2 == "panggilan") mengembalikan CallSessionContext baru (ini);
28 if (str2 == "thread_static") mengembalikan ThreadStaticSessionContext(ini);
29 if (str2 == "web") mengembalikan WebSessionContext baru (ini);
30 if (str2 == "managed_web") mengembalikan ManagedWebSessionContext baru (ini);
31}
32 lainnya
33 mengembalikan nol;
34 mencoba
35 {
36 Jenis tipe = ReflectHelper.ClassForName(nama);
37 kembali (ICurrentSessionContext) Lingkungan.BytecodeProvider.ObjectsFactory
38.CreateInstance(ketik, objek baru[] { ini });
39 }
40 tangkapan (Pengecualian pengecualian)
41 {
42 log.Error("Tidak dapat membuat konteks sesi saat ini [" + nama + "]", pengecualian);
43 mengembalikan nol;
44}
45 }
46 //......
47 }
Ketika SessionFactoryImpl dipakai, ia memanggil metode BuildCurrentSessionContext() (baris 21) untuk menetapkan nilai ke bidang currentSessionContext. Nilai spesifik ditentukan oleh current_session_context_class dalam file konfigurasi.
GetCurrentSession() dari ISessionFactory memanggil metode CurrentSession() (baris 6) dari ICurrentSessionContext.
Kode diatas cukup sederhana, semua orang pasti sudah memahaminya.
Ada dua tempat yang tidak pantas dalam artikel "Implementasi Sederhana NHibernate Satu Sesi Per Permintaan":
1. Tidak setiap permintaan memerlukan Sesi untuk mengakses database. Kode Global.asax dalam artikel menjalankan WebSessionContext.Bind() di awal semua permintaan, yang akan membuang banyak Sesi. Meskipun Sesi NHibernate ringan, pendekatan yang lebih masuk akal adalah "sangat membutuhkan" pengikatan waktu.
2. Karena metode WebSessionContext.Unbind memerlukan instance antarmuka ISessionFactory, kami terpaksa menggunakan kelas pembantu kami (NHibernateSessionFactory atau NHibernateHelper) untuk mengekspos SessionFactory.
Pertanyaan pertama lebih mudah dipecahkan, jadi tinggalkan pertanyaan itu di jawaban untuk berkomunikasi dengan semua orang.
Saya akan menjawab pertanyaan kedua di esai berikutnya.
Saya sudah lama tidak mempelajari NHibernate dan saya seorang pemula.