เพื่อนส่วนใหญ่ที่ใช้ NHibernate ในการพัฒนาเว็บรู้จักโหมด Session-Per-Request แต่มีตัวอย่างการใช้งานอย่างถูกต้องบนอินเทอร์เน็ตไม่มากนัก บทความมากมายบนอินเทอร์เน็ตรวมถึงในสวนก็ทำผิดพลาดแบบเดียวกัน และความผิดพลาดนี้ก็แพร่กระจายออกไป...
ก่อนอื่นเรามาดูบทความโดย Flyear ในสวน "NHibernate One Session Per Request Simple Implementation"
ไม่มีอะไรผิดปกติกับการกำหนดค่า NHibernate ก่อน:
<ชื่อคุณสมบัติ='current_session_context_class'>เว็บ</property>
ข้อผิดพลาดอยู่ในคลาส NHinbernateSessionFactory (ชื่อคลาสผิดทั้งหมด) NHinbernateSessionFactory.GetCurrentSession ไม่ควรรวมการดำเนินการบน HttpContext จริงๆ แล้ว GetCurrentSession ควรง่ายมาก โปรดดู (ชื่อคลาสเปลี่ยนเป็น NHibernateHelper)
NHibernateHelper ระดับปิดผนึกสาธารณะ
-
สาธารณะ ISessionFactory SessionFactory แบบอ่านอย่างเดียวแบบคงที่;
staticNHibernateHelper()
-
SessionFactory = การกำหนดค่าใหม่ ()
.กำหนดค่า()
.AddAssembly(/**/)
.BuildSessionFactory();
-
ISession GetCurrentSession สาธารณะแบบคงที่ ()
-
กลับ SessionFactory.GetCurrentSession();
-
-
กำหนดค่า current_session_context_class เป็นเว็บ และ NHibernate จะสร้างอินสแตนซ์ของคลาส NHibernate.Context.WebSessionContext ในระหว่างการกำหนดค่าเริ่มต้น ซอร์สโค้ดของคลาส WebSessionContext เป็นดังนี้:
[สามารถซีเรียลไลซ์ได้]
WebSessionContext คลาสสาธารณะ: MapBasedSessionContext
-
//ฟิลด์
สตริง const ส่วนตัว SessionFactoryMapKey = "NHibernate.Context.WebSessionContext.SessionFactoryMapKey";
// วิธีการ
WebSessionContext สาธารณะ (โรงงาน ISessionFactoryImplementor) : ฐาน (โรงงาน)
-
ป้องกันแทนที่ IDictionary GetMap()
-
กลับ (HttpContext.Current.Items [SessionFactoryMapKey] เป็น IDictionary);
-
ป้องกันแทนที่เป็นโมฆะ SetMap (ค่า IDictionary)
-
HttpContext.Current.Items[SessionFactoryMapKey] = ค่า;
-
-
WebSessionContext ใช้โหมด Session-Per-Request ซึ่งห่อหุ้ม HttpContext ดังนั้นเราจึงไม่จำเป็นต้องดำเนินการ HttpContext ในคลาสเสริมของเรา (NHibernateSessionFactory หรือ NHibernateHelper)
เราแค่ต้องได้รับเซสชันจากอินสแตนซ์ของ WebSessionContext การได้รับ ISession ปัจจุบันจากคลาส WebSessionContext นั้นค่อนข้างง่าย เนื่องจาก WebSessionContext ใช้อินเทอร์เฟซ ICurrentSessionContext:
อินเทอร์เฟซสาธารณะ ICurrentSessionContext
-
ISession CurrentSession();
-
คลาสและอินเทอร์เฟซในเนมสเปซ NHibernate.Context
(หมายเหตุ: current_session_context_class ยังสามารถกำหนดค่าเป็น Managed_web, Call, thread_static ซึ่งสอดคล้องกับคลาส ManagedWebSessionContext, CallSessionContext และ ThreadStaticSessionContext ตามลำดับ)
ในการใช้งานจริง เราไม่จำเป็นต้องเรียกใช้เมธอด CurrentSession() ของ WebSessionContext โดยตรง เนื่องจาก ISessionFactory มีวิธีการที่ง่ายกว่าซึ่งช่วยให้เราได้รับเซสชันในขั้นตอนเดียว:
อินเทอร์เฟซสาธารณะ ISessionFactory: IDisposable
-
ISession รับปัจจุบันเซสชั่น();
-
-
เรามาหารือเกี่ยวกับการใช้งานเฉพาะของเมธอด ISessionFactory.GetCurrentSession:
เมธอด Configuration.BuildSessionFactory ส่งคืนอินสแตนซ์ของคลาส SessionFactoryImpl เรามาดูรายละเอียดโค้ดบางส่วนของ SessionFactoryImpl กันดีกว่า:
1 คลาสที่ปิดผนึกสาธารณะ SessionFactoryImpl
2: ISessionFactoryImplementor, IMapping, ISessionFactory, IDisposable, IObjectReference
3 {
4 ส่วนตัวอ่านอย่างเดียว ICurrentSessionContext currentSessionContext;
5
6 ISession GetCurrentSession สาธารณะ ()
7 {
8 ถ้า (this.currentSessionContext == null)
9 {
10 โยน HibernateException ใหม่ (
11 "ไม่ได้กำหนดค่า CurrentSessionContext (ตั้งค่าคุณสมบัติ current_session_context_class)!");
12}
13 ส่งคืน this.currentSessionContext.CurrentSession();
14}
15
16 สาธารณะ ICurrentSessionContext CurrentSessionContext
17 {
18 รับ { กลับ this.currentSessionContext; }
19}
20
21 ส่วนตัว ICurrentSessionContext BuildCurrentSessionContext()
ยี่สิบสอง {
ชื่อสตริง 23 = PropertiesHelper.GetString("current_session_context_class", this.properties, null);
24 สตริง str2 = ชื่อ;
25 ถ้า (str2 != null)
26 {
27 ถ้า (str2 == "call") ส่งคืน CallSessionContext ใหม่ (สิ่งนี้);
28 ถ้า (str2 == "thread_static") ส่งคืน ThreadStaticSessionContext ใหม่ (สิ่งนี้);
29 ถ้า (str2 == "เว็บ") ส่งคืน WebSessionContext ใหม่ (สิ่งนี้);
30 ถ้า (str2 == "managed_web") ส่งคืน ManagedWebSessionContext ใหม่ (สิ่งนี้);
31}
32 อื่น ๆ
33 กลับเป็นโมฆะ;
34 ลอง
35 {
36 ประเภทประเภท = ReflectHelper.ClassForName(ชื่อ);
37 กลับ (ICurrentSessionContext) สภาพแวดล้อม BytecodeProvider.ObjectsFactory
38.CreateInstance(ประเภท, วัตถุใหม่[] { นี้ });
39 }
40 catch (ข้อยกเว้นข้อยกเว้น)
41 {
42 log.Error("ไม่สามารถสร้างบริบทเซสชั่นปัจจุบัน [" + ชื่อ + "]", ข้อยกเว้น);
43 กลับเป็นโมฆะ;
44}
45 }
46 //......
47 }
เมื่อ SessionFactoryImpl ถูกสร้างอินสแตนซ์ มันจะเรียกเมธอด BuildCurrentSessionContext() (บรรทัดที่ 21) เพื่อกำหนดค่าให้กับฟิลด์ currentSessionContext ค่าเฉพาะถูกกำหนดโดย current_session_context_class ในไฟล์คอนฟิกูเรชัน
GetCurrentSession() ของ ISessionFactory เรียกเมธอด CurrentSession() ของ ICurrentSessionContext (บรรทัด 6)
โค้ดด้านบนนั้นค่อนข้างง่าย ทุกคนต้องเข้าใจมันอยู่แล้ว
มีสถานที่ที่ไม่เหมาะสมสองตำแหน่งในบทความ "NHibernate One Session Per Request Simple Implementation":
1. ไม่ใช่ทุกคำขอที่จำเป็นต้องมีเซสชันในการเข้าถึงฐานข้อมูล รหัสของ Global.asax ในบทความดำเนินการ WebSessionContext.Bind() ที่จุดเริ่มต้นของคำขอทั้งหมด ซึ่งจะทำให้เซสชันของ NHibernate มีน้ำหนักเบา แต่แนวทางที่สมเหตุสมผลกว่าคือการผูกเวลา "ต้องการจริงๆ"
2. เนื่องจากเมธอด WebSessionContext.Unbind จำเป็นต้องมีอินสแตนซ์ของอินเทอร์เฟซ ISessionFactory เราจึงถูกบังคับให้ใช้คลาสตัวช่วยของเรา (NHibernateSessionFactory หรือ NHibernateHelper) เพื่อเปิดเผย SessionFactory
คำถามแรกแก้ได้ง่ายกว่า ดังนั้นฝากไว้ในการตอบกลับเพื่อสื่อสารกับทุกคน
ฉันจะตอบคำถามที่สองในเรียงความถัดไป
ฉันไม่ได้เรียน NHibernate มานานแล้วและเป็นมือใหม่ หากมีข้อผิดพลาดใด ๆ โปรดแก้ไขฉันด้วย!