1. การทำแผนที่มรดก
การสืบทอดเป็นคุณสมบัติที่มุ่งเน้นวัตถุที่สำคัญ มันใช้การใช้รหัสและยังมีความสัมพันธ์ในการสืบทอดในรูปแบบความสัมพันธ์ ความสัมพันธ์การสืบทอดนี้สามารถถือได้ว่าเป็นความสัมพันธ์ที่แจงนับ ชนิดย่อยจำนวนมากสามารถระบุได้ในประเภท ชนิดย่อยเหล่านี้ก่อให้เกิดความสัมพันธ์ในการสืบทอดกับวัตถุหลัก การแจกแจงส่วนใหญ่ที่สามารถแจกแจงได้ถือได้ว่าเป็นแผนที่มรดก ดังนั้นความสัมพันธ์การแจงนับนี้จึงถือได้ว่าเป็นแผนที่มรดก ตัวอย่างเช่นสัตว์เป็นชนชั้นนามธรรมซึ่งเป็นคลาสแม่ของสัตว์อื่น ๆ หมูแมว ฯลฯ และเป็นความสัมพันธ์ที่สืบทอดมาดังแสดงในรูปด้านล่าง:
การทำแผนที่การสืบทอดนี้จะสร้างตารางหลังจากแปลงเป็นแบบจำลองเชิงสัมพันธ์ ดังนั้นตารางนี้แยกความแตกต่างระหว่างสองประเภทนี้อย่างไร ใช้ฟิลด์เชิงสัมพันธ์คุณต้องเพิ่มฟิลด์ประเภทลงในตารางและใช้คำหลักเพื่อระบุประเภทของวัตถุ ดังนั้นโครงสร้างตารางที่สอดคล้องกับโมเดลวัตถุในรูปด้านบนมีดังนี้:
เมื่อสร้างโครงสร้างตารางคุณจะต้องเพิ่มประเภทฟิลด์ที่เกี่ยวข้องดังนั้นคุณต้องเพิ่มตัวเลือกแผนที่แผนที่ที่สอดคล้องกันลงในไฟล์การแมป ที่นี่คุณต้องใช้แอตทริบิวต์ discriminator-value
1. ไฟล์คลาส
ไม่จำเป็นต้องให้ความสนใจกับไฟล์ชั้นเรียนเพียงแค่ให้ความสนใจกับความสัมพันธ์ระหว่างพวกเขาเมื่อเขียน
รายชื่อ: รหัสคลาสสัตว์คุณจะต้องเพิ่มคุณสมบัติพื้นฐานเท่านั้น
แพ็คเกจ com.src.hibernate; Animal Class Public {// หมายเลข ID ID int ส่วนตัว; สาธารณะ int getId () {return id; } โมฆะสาธารณะ setId (int id) {this.id = id; } // ชื่อชื่อสตริงส่วนตัว; สตริงสาธารณะ getName () {ชื่อคืน; } โมฆะสาธารณะ setName (ชื่อสตริง) {this.name = name; } // เพศบูลีนส่วนตัวเพศ; บูลีนสาธารณะ iSsex () {กลับเซ็กส์; } โมฆะสาธารณะ setsex (เพศบูลีน) {this.sex = เพศ; -รายการ 2: ชั้นเรียนนกและหมูเพิ่มคุณสมบัติพื้นฐานและการสืบทอดคลาสสัตว์
แพ็คเกจ com.src.hibernate; นกชั้นสาธารณะขยายสัตว์ {// ความสูงความสูงส่วนตัว public int getheight () {return height; } โมฆะสาธารณะ setheight (ความสูง int) {this.height = ความสูง; }} แพ็คเกจ com.src.hibernate; หมูชั้นสาธารณะขยายสัตว์ {// น้ำหนักส่วนตัวน้ำหนัก สาธารณะ int getweight () {น้ำหนักกลับ; } โมฆะสาธารณะ setweight (น้ำหนัก int) {this.weight = น้ำหนัก; - 2. ไฟล์แผนที่
การแมปที่สอดคล้องกันจะต้องเพิ่มลงในไฟล์การแมป ต้องเพิ่มไฟล์การแมปเพียงหนึ่งไฟล์ลงในโมเดลเนื่องจากมีเพียงหนึ่งตารางเท่านั้นที่ถูกสร้างขึ้นการแมปย่อยที่สอดคล้องกันจะถูกเพิ่มเข้าไปในไฟล์การแมป ใช้แท็ก <class> และเพิ่มค่า discriminator-value ลงในแท็ก คุณสมบัติ discriminator นี้ระบุประเภทที่เขียนเมื่อเขียนข้อมูลในฐานข้อมูลดังนี้:
<? xml เวอร์ชัน = "1.0"?> <! Doctype hibernate-mapping สาธารณะ "-// hibernate/hibernate mapping dtd 3.0 // en" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" table = "t_animal"> <id name = "id"> <generator // id> <!-เพิ่มแท็กการรับรองความถูกต้องและต้องวางไว้หลังจาก ID-> <discriminator column = "type"/> <property name = "name"/> <property name = "sex" type = "boolean"/> name = "weight"/> </subclass> <subclass name = "com.src.hibernate.bird" discriminator-value = "b"> <property name = "ความสูง"/> </subclass> </class> </hibernate-mapping>
3. ผลการวิเคราะห์
ตารางฐานข้อมูล MySQL ที่สร้างขึ้นไม่เพียง แต่จะเพิ่มคุณลักษณะพื้นฐานของสัตว์ แต่ยังเพิ่มคุณสมบัติของหมูและนก เนื่องจากแอตทริบิวต์ที่เพิ่มเข้ามานั้นเขียนขึ้นโดยใช้ <subclass> ในไฟล์การแมปและแอตทริบิวต์ discriminator ที่สอดคล้องกันจะถูกเพิ่มเข้ามาดังนั้นคอลัมน์ discriminator ที่สอดคล้องกันจะถูกเพิ่มลงในฐานข้อมูล โครงสร้างตารางที่สร้างขึ้นมีดังนี้:
2. การทำงานของข้อมูล
1. ข้อมูลเขียน
เมื่อทำการอ่านข้อมูลและการเขียนคุณต้องใส่ใจกับการใช้งานในชั้นเรียน
การทดสอบโมฆะสาธารณะ () {เซสชันเซสชัน = null; ลอง {// สร้าง Session Object Session = HiberNateUtils.getSession (); // เปิดเซสชันการทำธุรกรรม BEGINTRANSACTION (); หมูหมู = หมูใหม่ (); Pig.setName ("Little Pig"); Pig.Setsex (จริง); Pig.Setweight (200); เซสชั่น SAVE (หมู); นกนก = นกตัวใหม่ (); Bird.setName ("Xiaoniao"); Bird.setsex (จริง); Bird.Setheight (100); เซสชั่น SAVE (นก); session.getTransaction (). commit (); } catch (exception e) {e.printstacktrace (); session.getTransaction (). ย้อนกลับ (); } ในที่สุด {hibernateutils.closesession (เซสชัน); -2. Polymorphic Query-Get และ HQL
วิธีการสืบค้นพื้นฐานต้องใช้วิธีการโหลดและรับเท่านั้น ที่นี่เรามุ่งเน้นไปที่การสืบค้น polymorphic Polymorphic Query หมายความว่า Hibernate สามารถใช้อินสแตนซ์ของเพื่อระบุประเภทของวัตถุที่แท้จริงเมื่อโหลดวัตถุเพื่อให้สามารถเป็นแบบสอบถาม polymorphic
หมายเหตุ: การสืบค้น polymorphic ไม่รองรับการโหลดขี้เกียจนั่นคือถ้าคุณใช้วิธีการโหลดคุณต้องตั้งค่าการโหลดขี้เกียจเป็นเท็จในไฟล์การแมป
3. โหลดการโหลดล่าช้า
โหลดรองรับการโหลดขี้เกียจ เมื่อโหลดวัตถุมันจะสร้างพร็อกซีของวัตถุ ดังนั้นเมื่อใช้แบบสอบถาม polymorphic คุณต้องตั้งค่าการโหลดขี้เกียจเป็นเท็จในไฟล์การแมปดังต่อไปนี้:
<? xml เวอร์ชัน = "1.0"?> <! Doctype hibernate-mapping สาธารณะ "-// hibernate/hibernate mapping dtd 3.0 // en" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" table = "t_animal" lazy = "false"> <id name = "id"> <generator // id> <!-เพิ่มแท็กการรับรองความถูกต้องและต้องวางไว้หลังจาก ID-> <discriminator column = "type"/> <property name = "name"/> <property name = "sex" type = "boolean" discriminator-value = "p"> <property name = "weight"/> </subclass> <subclass name = "com.src.hibernate.bird" discriminator-value = "b"> <property name = "ความสูง"/>
วิธีการโหลดโหลดโดยใช้โหลดเพื่อโหลดตัวอย่างนี้รองรับแบบสอบถาม polymorphic และตั้งค่าการโหลดล่าช้าเป็นเท็จในไฟล์การกำหนดค่าดังนั้นวิธีการโหลดสามารถใช้ที่นี่เพื่อโหลดและรับคลาสวัตถุที่เกี่ยวข้อง
public void testload () {เซสชันเซสชัน = null; ลอง {session = hibernateutils.getSession (); session.beginTransaction (); Animal ani = (สัตว์) เซสชั่นโหลด (iment.class, 1); System.out.println (ani.getName ()); // เนื่องจากโหลดรองรับขี้เกียจโดยค่าเริ่มต้นเราเห็นพร็อกซีของสัตว์ // ดังนั้นอินสแตนซ์ของไม่สามารถระบุหมูชนิดที่แท้จริง // ดังนั้นโหลดไม่รองรับแบบสอบถาม polymorphic ในกรณีนี้ถ้า (ani instanceof pig) {system.out.println ("ฉันเป็นหมู!"); } else {system.out.println ("ฉันไม่ใช่หมู!"); } session.getTransaction (). commit (); } catch (exception e) {e.printstacktrace (); session.getTransaction (). ย้อนกลับ (); } ในที่สุด {hibernateutils.closesession (เซสชัน); - 4.HQL แบบสอบถาม
HQL รองรับการสืบค้น polymorphic ซึ่งส่วนใหญ่เป็นเพราะการสืบค้นเป็นวัตถุจริงและไม่คืนพร็อกซี ดังนั้น HQL จึงรองรับการสืบค้นแบบ polymorphic นอกจากนี้เมื่อสอบถามคุณต้องใส่ใจที่จะไม่ใช้ชื่อตารางในคำสั่ง Query แต่ใช้ชื่อคลาส ไฮเบอร์เนตจะแมปกับชื่อตารางที่เกี่ยวข้องตามชื่อคลาสดังนี้:
โมฆะสาธารณะ testload5 () {เซสชันเซสชัน = null; ลอง {session = hibernateutils.getSession (); session.beginTransaction (); รายการ <imant> list = session.createquery ("จาก Animal"). list (); สำหรับ (iterator iter = list.iterator (); iter.hasnext ();) {สัตว์ a = (สัตว์) iter.next (); if (a instanceof pig) {system.out.println ("ฉันเป็นหมู!"); } else {system.out.println ("ฉันไม่ใช่หมู!"); }} session.getTransaction (). commit (); } catch (exception e) {e.printstacktrace (); session.getTransaction (). ย้อนกลับ (); } ในที่สุด {hibernateutils.closesession (เซสชัน); -ผลลัพธ์การสอบถาม:
ไฮเบอร์เนต: เลือก Animal0_.id เป็น id0_, iment0_.name เป็นชื่อ 0_, iment0_.sex เป็น sex0_, iment0_.weight as weight0_, iment0_.height เป็น height0_, iment0_.type เป็น type0_ จาก t_animal imental0_ ฉันเป็นลูกหมู! ฉันไม่ใช่หมู! ฉันเป็นลูกหมู! ฉันไม่ใช่หมู!
3. สามกลยุทธ์สำหรับการทำแผนที่มรดก
1. ตารางต่อลำดับชั้นเรียน
สมมติว่าเรามีการชำระเงินแบบอินเทอร์เฟซและคลาสการดำเนินการหลายอย่าง: CreditCardPayment, CASHPAYMENT และ CHEQUEPALEMENT จากนั้นรหัสการแมปของ "ตารางต่อลำดับชั้นเรียน" มีดังนี้:
<class name = "การชำระเงิน" table = "การชำระเงิน"> <id name = "id" type = "long" คอลัมน์ = "payment_id"> <generator/> </id> <discriminator column = "Payment_type" type = "String"/> <property name = "จำนวน" จำนวน " column = "cctype"/> ... </subclass> <subclass name = "cashepayment" discriminator-value = "เงินสด"> ... </subclass> <subclass name = "chequepayment" discriminator-value = "ตรวจสอบ"> ...
จำเป็นต้องใช้เพียงตารางเดียวในการใช้กลยุทธ์นี้ มันมีข้อ จำกัด ที่ยิ่งใหญ่: มันต้องการให้ฟิลด์ที่กำหนดโดยคลาสย่อยเช่น CCType ไม่สามารถมีข้อ จำกัด ที่ไม่ใช่ข้อ จำกัด ได้
2. หนึ่งตารางต่อคลาสย่อย
สำหรับคลาสในตัวอย่างข้างต้นกลยุทธ์การทำแผนที่ของ "หนึ่งตารางต่อคลาสย่อย" ถูกนำมาใช้และรหัสมีดังนี้:
<class name = "การชำระเงิน" table = "การชำระเงิน"> <id name = "id" type = "long" คอลัมน์ = "payment_id"> <generator/> </id> <property name = "จำนวน" คอลัมน์ = "จำนวน"/> ... name = "cailpayment" table = "cash_payment"> <คีย์คอลัมน์ = "payment_id"/> <property name = "creditCardType" คอลัมน์ = "cctype"/> ...
ต้องใช้สี่ตาราง ตารางย่อยสามตารางนั้นเชื่อมโยงกับตารางซูเปอร์คลาสผ่านคีย์หลัก (ดังนั้นรูปแบบความสัมพันธ์จึงเป็นความสัมพันธ์แบบหนึ่งต่อหนึ่ง)
3. แต่ละคลาสย่อยมีตาราง (ตารางต่อคลาสย่อย) และใช้ discriminator
โปรดทราบว่าสำหรับกลยุทธ์การทำแผนที่ของ "หนึ่งตารางต่อคลาสย่อย" การใช้งานไฮเบอร์เนตไม่จำเป็นต้องใช้ฟิลด์ discriminator ในขณะที่เครื่องมือการแมปวัตถุ/ความสัมพันธ์อื่น ๆ ใช้วิธีการใช้งานที่แตกต่างจากไฮเบอร์เนตซึ่งต้องใช้คอลัมน์จำแนกประเภทในตาราง SuperClass วิธีการที่ใช้โดยไฮเบอร์เนตนั้นยากที่จะนำไปใช้ แต่จากมุมมองของความสัมพันธ์ (ฐานข้อมูล) มันถูกต้องมากกว่า หากคุณเต็มใจที่จะใช้กลยุทธ์ "หนึ่งตารางต่อคลาสย่อย" กับฟิลด์ Discernment คุณสามารถใช้ <class> ด้วย <Oin> ดังนี้:
<class name = "การชำระเงิน" table = "การชำระเงิน"> <id name = "id" type = "long" คอลัมน์ = "payment_id"> <generator/> </id> <discriminator column = "Payment_type" type = "String"/> <property name = "จำนวน" <property name = "CreditCardType" คอลัมน์ = "cctype"/> ... </join> </subclass> <subclass name = "CASHPAYMENT" discriminator-value = "เงินสด"> <เข้าร่วม table = "Cash_Payment"> ... table = "cheque_payment" fetch = "select"> ... </join> </subclass> </class> </class>
การประกาศเพิ่มเติม fetch = "select" ถูกใช้เพื่อบอก Hibernate ว่าเมื่อสอบถาม superclasses อย่าใช้การเข้าร่วมภายนอกเพื่อคว้าข้อมูลของ subclass chequepayment