1. การทำแผนที่การเชื่อมโยงทางเดียวแบบหนึ่งต่อหลายครั้ง
แบบจำลองวัตถุของความสัมพันธ์แบบหนึ่งถึงหลายคนมักจะเห็นในชีวิตประจำวัน นำนักเรียนและชั้นเรียนเป็นตัวอย่าง มีนักเรียนหลายคนในชั้นเรียนดังนั้นความสัมพันธ์ระหว่างชั้นเรียนและนักเรียนจึงเป็นความสัมพันธ์แบบหนึ่งถึงหลายคนที่แมปเข้ากับโมเดลวัตถุดังที่แสดงในรูปด้านล่าง:
โมเดลวัตถุแสดงให้เห็นว่าความสัมพันธ์แบบหนึ่งถึงหลายคนนี้ได้รับการบำรุงรักษาโดยปลายด้านหนึ่งดังนั้นการทำแผนที่ในรูปแบบความสัมพันธ์หมายความว่าจะมีนักเรียนหลายคนภายใต้สาขาชั้นเรียนซึ่งเป็นความสัมพันธ์แบบหนึ่งต่อหลายคน ข้อมูลนักเรียนสามารถรับได้ผ่านชั้นเรียน รูปแบบความสัมพันธ์ที่สอดคล้องกันมีดังนี้:
1. การกำหนดค่าพื้นฐาน
ด้วยโมเดลวัตถุจากนั้นแมปไว้ในรหัสความสัมพันธ์ที่สอดคล้องกัน เมื่อทำการแมปความสัมพันธ์คุณจะต้องเพิ่มแท็ก <หนึ่งถึงหลายคน> ที่ปลายด้านหนึ่ง นอกจากนี้คุณต้องเพิ่มแอตทริบิวต์ชุดที่ปลายด้านหนึ่ง รองรับการโหลดขี้เกียจจากนั้นเพิ่มแท็กชุดในไฟล์การแมปและระบุความสัมพันธ์แบบหนึ่งต่อหลายคนเพื่อให้คุณสามารถสอบถามและรับจุดสิ้นสุดหลายด้านที่ปลายด้านหนึ่ง
คลาสและไฟล์การแมป:
มันเป็นจุดสิ้นสุดที่สำคัญที่สุดของโมเดล ในตอนท้ายนี้คุณต้องเพิ่มแอตทริบิวต์ชุดที่เกี่ยวข้องและเพิ่มแท็กชุดในไฟล์การกำหนดค่า คุณสามารถกำหนดค่าวัตถุ <หนึ่งต่อหลาย ๆ ได้ที่สอดคล้องกันในแท็กชุด รหัสวัตถุที่เฉพาะเจาะจงรหัสวัตถุ Java มีดังนี้:
แพ็คเกจ com.src.hibernate; นำเข้า java.util.set; ชั้นเรียนสาธารณะ {ID INT ส่วนตัว; สาธารณะ int getId () {return id; } โมฆะสาธารณะ setId (int id) {this.id = id; } สตริงสาธารณะ getName () {ชื่อคืน; } โมฆะสาธารณะ setName (ชื่อสตริง) {this.name = name; } ชื่อสตริงส่วนตัว; // ตั้งค่าสนับสนุนการโหลดขี้เกียจของนักเรียนชุดส่วนตัว; Set Public Set GetStudents () {ส่งคืนนักเรียน; } public void setstudents (ตั้งค่านักเรียน) {this.students = นักเรียน; -แอตทริบิวต์ชุดใช้ในวัตถุคลาส แต่จะอธิบายเฉพาะแอตทริบิวต์การโหลดล่าช้าและไม่ได้กำหนดค่าวัตถุที่เกี่ยวข้องสำหรับแอตทริบิวต์ วัตถุของแอตทริบิวต์จะต้องกำหนดค่าในไฟล์การแมป คุณต้องเพิ่มแท็กชุดและเพิ่มแท็ก <หนึ่งต่อหลายคน> ลงในแท็กชุด รหัสเฉพาะมีดังนี้:
<? xml เวอร์ชัน = "1.0"?> <! Doctype hibernate-mapping สาธารณะ "-// hibernate/hibernate mapping dtd 3.0 // en" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" table = "t_classes"> <id name = "id"> <generator // id> <property name = "name"/> <set name = "นักเรียน"> <key column = "classesid"> </key> <one-to-many> </one-to-many> </set> </class>
ไฟล์รหัสและการแมปในวัตถุนักเรียนที่เกี่ยวข้องไม่จำเป็นต้องมีการกำหนดค่าพิเศษใด ๆ พวกเขาจะต้องเขียนตามวิธีการเขียนปกติเท่านั้น วิธีการกำหนดค่าเฉพาะจะไม่ได้รับการอธิบายในรายละเอียดมันง่ายมาก หลังการกำหนดค่าคุณต้องสร้างคำสั่ง SQL ที่เกี่ยวข้อง เมื่อแปลงโมเดลวัตถุเป็นแบบจำลองเชิงสัมพันธ์ไฮเบอร์เนตจะสร้างคำสั่งที่เกี่ยวข้องดังนี้:
เปลี่ยนตาราง t_student drop key ต่างประเทศ fk4b9075705e0afefe drop table ถ้ามี t_classes drop table ถ้ามี t_student สร้างตาราง t_classes (ID จำนวนเต็มไม่ใช่ null auto_increment, ชื่อ varchar (255), คีย์หลัก (id)) จำนวนเต็ม, คีย์หลัก (ID)) เปลี่ยนตาราง t_student เพิ่มดัชนี FK4B9075705E0AFEFE (classESID), เพิ่มข้อ จำกัด FK4B9075705E0AFEFEFEFE FANRAFORM
รูปแบบความสัมพันธ์ที่สอดคล้องกันที่สร้างขึ้นแสดงด้านล่าง:
การเปรียบเทียบคำสั่ง SQL และแบบจำลองความสัมพันธ์ความสัมพันธ์ระหว่างตารางที่เกี่ยวข้องจะถูกเก็บรักษาไว้ผ่านคีย์ต่างประเทศ ขั้นแรกให้สร้างสองตารางระบุคีย์หลักของตารางและในที่สุดก็เพิ่มความสัมพันธ์สมาคมคีย์ต่างประเทศแบบหนึ่งถึงหลายคน
2. การดำเนินการขั้นพื้นฐาน
การดำเนินการในฐานข้อมูลไม่มีอะไรมากไปกว่าการอ่านและเขียนและการปรับเปลี่ยนเป็นประเภทของการเขียน ถัดไปมาดูวิธีการเขียนและอ่านการดำเนินการลงในฐานข้อมูล
(1) เขียนข้อมูล:
เมื่อเขียนข้อมูลคุณต้องให้ความสนใจกับความสัมพันธ์แบบหนึ่งต่อหลายคนดังนั้นคุณต้องเพิ่มชั้นเรียนนักเรียนหลายชั้นเมื่อเพิ่มพวกเขา นอกจากนี้เนื่องจากแอตทริบิวต์ชุดที่สอดคล้องกันถูกเพิ่มเข้าไปในคลาสคุณควรใช้ HashSet เพื่อเพิ่มเมื่อเพิ่มวัตถุนักเรียนดังนั้นคุณจึงสามารถตระหนักถึงความสัมพันธ์แบบหนึ่งต่อหลายคน รหัสเฉพาะมีดังนี้:
โมฆะสาธารณะ testSave2 () {เซสชันเซสชัน = null; ลอง {session = hibernateutils.getSession (); session.beginTransaction (); นักเรียนนักเรียน 1 = นักเรียนใหม่ (); student1.setName ("จาง"); เซสชัน SAVE (Student1); นักเรียนนักเรียน 2 = นักเรียนใหม่ (); student2.setName ("lisi"); เซสชัน SAVE (Student2); คลาสคลาส = คลาสใหม่ (); classes.setName ("classOne"); ตั้งค่านักเรียน = new hashset (); นักเรียน ADD (นักเรียน 1); นักเรียน ADD (Student2); ชั้นเรียนนักเรียน (นักเรียน); // ข้อมูลสามารถบันทึกได้สำเร็จ // แต่คำสั่งการอัปเดตพิเศษจะออกเพื่อรักษาความสัมพันธ์เพราะเป็นหนึ่งในการใช้เหตุผลหนึ่งในหลาย ๆ session.getTransaction (). commit (); } catch (exception e) {e.printstacktrace (); session.getTransaction (). ย้อนกลับ (); } ในที่สุด {hibernateutils.closesession (เซสชัน); - จากนั้นหลังจากข้อมูลที่เกี่ยวข้องที่สร้างขึ้นโดยการเรียกใช้กรณีทดสอบด้านบนจะถูกเขียนลงในฐานข้อมูลตัวเลขต่อไปนี้มีดังนี้:
(2) อ่านข้อมูล:
การดำเนินการเขียนค่อนข้างง่าย คุณจะต้องเพิ่มวัตถุที่โหลดทั้งหมดลงในสถานะชั่วคราวและเรียกใช้วิธีการที่สอดคล้องกันเพื่อแทรกเนื้อหา อย่างไรก็ตามการดำเนินการอ่านที่สอดคล้องกันจะซับซ้อนขึ้นเล็กน้อย เนื่องจากมีความจำเป็นที่จะต้องทำซ้ำเพื่อให้ได้วัตถุนักเรียนทั้งหมดความสัมพันธ์แบบหนึ่งต่อหลายคนนี้ไม่ได้มีประสิทธิภาพมากนัก รหัสเฉพาะมีดังนี้:
แพ็คเกจ com.test.hibernate; นำเข้า java.util.iterator; นำเข้า java.util.set; นำเข้า com.src.hibernate.*; นำเข้า junit.framework.testcase; นำเข้า org.hibernate.session; ชั้นเรียนสาธารณะ One2ManyTest ขยาย TestCase {โมฆะสาธารณะ testload1 () {เซสชันเซสชัน = null; ลอง {session = hibernateutils.getSession (); session.beginTransaction (); // รับข้อมูลชั้นเรียนด้วยคลาสหลัก 5 คลาสคลาส = (คลาส) เซสชันการโหลด (classes.class, 5); // พิมพ์ข้อมูลคลาส System.out.println ("classes.name ="+classes.getName ()); // ตั้งค่าชุดนักเรียนและโหลดชุดนักเรียนผ่านชุดชั้นเรียนนักเรียน = classes.getStudents (); // ซ้ำชุดและพิมพ์ข้อมูลนักเรียนในชุดสำหรับ (iterator iter = students.iterator (); iter.hasnext ();) {นักเรียนนักเรียน = (นักเรียน) iter.next (); System.out.println ("student.name ="+student.getName ()); } session.getTransaction (). commit (); } catch (exception e) {e.printstacktrace (); session.getTransaction (). ย้อนกลับ (); } ในที่สุด {hibernateutils.closesession (เซสชัน); -ข้อความที่เกี่ยวข้องและข้อมูลที่สร้างขึ้นมีดังนี้:
Hibernate: เลือก classes0_.id เป็น id1_0_, classes0_.name เป็น name1_0_ จาก t_classes classes0_ โดยที่ classes0_.id =? classes.name = classOne hibernate: เลือกนักเรียน 0_.classesid เป็น classid1_, students0_.id เป็น id1_, นักเรียน 0_.id เป็น id0_0_, นักเรียน 0_.name เป็น name0_0_ จากนักเรียน t_student0_ ที่นักเรียน 0_.classesid =? Student.Name = Lisi Student.Name = Zhangsan
2. การทำแผนที่การเชื่อมโยงแบบสองทิศทางแบบหนึ่งถึงหลายครั้ง
ที่นี่เรายังคงใช้นักเรียนและชั้นเรียนเป็นตัวอย่าง มีความสัมพันธ์แบบหนึ่งถึงหลายคนระหว่างชั้นเรียนและนักเรียน มีนักเรียนหลายคนในชั้นเรียน ซึ่งแตกต่างจากบทความก่อนหน้าความสัมพันธ์ที่นี่คือสองทางนั่นคือปลายด้านหนึ่งและปลายด้านหนึ่งรักษาความสัมพันธ์ในเวลาเดียวกันดังนั้นแผนภาพของวัตถุมีดังนี้:
แผนภาพโมเดลความสัมพันธ์ที่สอดคล้องกันไม่ได้เปลี่ยนแปลงมากนักเนื่องจากความสัมพันธ์ระหว่างพวกเขาเป็นแบบสองทิศทางดังนั้นทั้งสองด้านของแบบจำลองความสัมพันธ์จะรักษาความสัมพันธ์ในเวลาเดียวกันและทำแผนที่กับโมเดลความสัมพันธ์ดังแสดงในรูปด้านล่าง:
ในการเชื่อมโยงทางเดียวแบบหนึ่งถึงหลายครั้งไฟล์การแมปจะต้องได้รับการกำหนดค่าเป็นพิเศษในปลายด้านหนึ่ง ใช้การกำหนดค่า <หนึ่งต่อหลายครั้ง> และใช้ชุด iterator ในโมเดลวัตถุเพื่อตั้งค่าโมเดลวัตถุที่ไม่มีการเชื่อมโยง อย่างไรก็ตามความแตกต่างคือในการเชื่อมโยงสองทางสมาคมคีย์ต่างประเทศที่สอดคล้องกันที่ปลายอีกด้านจะต้องเพิ่มในหลาย ๆ ปลาย ในเวลานี้จะต้องใช้ความสัมพันธ์ของ <หลายต่อหนึ่ง-หนึ่ง> ในหลาย ๆ จุดเพื่อระบุความเป็นไปได้แบบสองทิศทางนี้
1. การทำแผนที่
ชั้นเรียนและนักเรียนยังใช้เป็นตัวอย่างที่นี่ เนื้อหาในชั้นเรียนสิ้นสุดนั้นเหมือนกับด้านบนและจะไม่เปลี่ยนแปลง แต่การกำหนดค่าของนักเรียนในหลาย ๆ ด้านจะเปลี่ยนไปนั่นคือแท็ก <หลายต่อหนึ่งถึงหนึ่ง> จะต้องเพิ่มลงในไฟล์การแมป
การกำหนดค่าไฟล์การแมปของนักเรียน. hbm.xml ต้องเพิ่มคอลัมน์คีย์ต่างประเทศ <หลายต่อหนึ่ง> แท็กและชื่อของคอลัมน์จะต้องสอดคล้องกับชื่อของคอลัมน์คีย์ต่างประเทศของคลาส hbm.xml รหัสเฉพาะมีดังนี้:
<? xml เวอร์ชัน = "1.0"?> <! Doctype hibernate-mapping สาธารณะ "-// hibernate/hibernate mapping dtd 3.0 // en" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" table = "t_student"> <id name = "id"> <generator/generator/> </id> <property name = "name"/> <!-เพิ่มคอลัมน์คลาสใหม่ในนักเรียนในด้านหนึ่งและชื่อคอลัมน์ควรเป็นรายการเดียวกันกับคลาส
การกำหนดค่าของไฟล์การแมปคลาส HBM.XML นั้นเหมือนกับในบทความก่อนหน้า ควรสังเกตว่าการแมปแอตทริบิวต์ชุดจะถูกเพิ่มลงในไฟล์ classes.java และสอดคล้องกับวัตถุนักเรียน ดังนั้นจึงจำเป็นต้องเพิ่มแท็กชุดลงในไฟล์การแมปเพื่อระบุว่าตัววนซ้ำชุดจะใช้ในโมเดลวัตถุ การกำหนดค่าเฉพาะมีดังนี้:
<? xml เวอร์ชัน = "1.0"?> <! Doctype hibernate-mapping สาธารณะ "-// hibernate/hibernate mapping dtd 3.0 // en" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" table = "t_classes"> <id name = "id"> <generator // id> <property name = "name"/> <set name = "นักเรียน" inverse = "true"> <key column = "classesid"> </key>
2. ชั้นเรียน
การกำหนดค่าของไฟล์การแมปตรงกับคลาสโดยตรงดังนั้นด้วยไฟล์การแมปคุณสามารถเขียนคลาสที่เกี่ยวข้อง ด้วยคลาสเดียวกันคุณสามารถรู้วิธีการเขียนไฟล์การแมปที่เกี่ยวข้อง มาดูวิธีการเขียนรหัสคลาสที่เกี่ยวข้อง
student.java คลาสต้องเพิ่มแอตทริบิวต์วัตถุคลาสที่เกี่ยวข้องในชั้นเรียนและคุณสามารถรับข้อมูลที่เกี่ยวข้องกับชั้นเรียนเมื่อโหลดนักเรียน
แพ็คเกจ com.src.hibernate; นักเรียนชั้นเรียนสาธารณะ {// ชั้นเรียนคลาสเรียนชั้นเรียนที่เกี่ยวข้องชั้นเรียนส่วนตัว; คลาสสาธารณะ getClasses () {คลาสกลับ; } โมฆะสาธารณะ setClasses (คลาสคลาส) {this.classes = คลาส; } // ID นักเรียน ID ส่วนตัว ID; สาธารณะ int getId () {return id; } โมฆะสาธารณะ setId (int id) {this.id = id; } // ชื่อนักเรียนชื่อสตริงส่วนตัว; สตริงสาธารณะ getName () {ชื่อคืน; } โมฆะสาธารณะ setName (ชื่อสตริง) {this.name = name; - เนื้อหารหัสเฉพาะของไฟล์ class.java แสดงในบทความก่อนหน้าและจะไม่ถูกอธิบายในรายละเอียดที่นี่
ด้วยโมเดลวัตถุโมเดลความสัมพันธ์จะถูกสร้างขึ้น คำสั่ง SQL ที่สร้างขึ้นมีดังนี้:
เปลี่ยนตาราง t_student drop คีย์ต่างประเทศ fk4b907570fc588bf4 ตาราง drop หากมี t_classes drop table ถ้ามี t_student สร้างตาราง t_classes (ID จำนวนเต็มไม่ใช่ null auto_increment, Name NOMD, NAME, VARCHARCHAR (255), คีย์หลัก (ID) จำนวนเต็ม, คีย์หลัก (ID)) เปลี่ยนตาราง t_student เพิ่มดัชนี FK4B907570FC588BF4 (คลาส SID) เพิ่มข้อ จำกัด FK4B907570FC588BF4 คีย์ต่างประเทศ (คลาสสิก) การอ้างอิง T_CLASSES (ID)
3. การทำงานของข้อมูล
หลังจากสร้างโครงสร้างตารางฉันเขียนวิธีทดสอบเพื่อตรวจสอบการทำงานของข้อมูล ก่อนอื่นมาดูการแทรกข้อมูลและแทรกข้อมูลลงในโครงสร้างตาราง มีสองสถานการณ์เมื่อเขียนข้อมูล หนึ่งคือการสร้างวัตถุคลาสก่อนเขียนวัตถุไปยังฐานข้อมูลจากนั้นสร้างวัตถุนักเรียนและเพิ่มวัตถุนักเรียนลงในวัตถุคลาส อีกอย่างคือการสร้างวัตถุนักเรียนก่อนเขียนวัตถุนักเรียนไปยังฐานข้อมูลจากนั้นสร้างวัตถุคลาสเพื่อเพิ่มวัตถุนักเรียนลงในวัตถุคลาส การดำเนินการทั้งสองประเภทนี้แตกต่างกันในที่สุดดังนั้นให้เปรียบเทียบกัน
3.1 เขียนชั้นเรียนก่อนจากนั้นเขียนนักเรียน
หลังจากเขียนคลาสไปยังฐานข้อมูลก่อนวัตถุคลาสจะเข้าสู่สถานะชั่วคราวและมีแถวในฐานข้อมูล จากนั้นเขียนวัตถุนักเรียน วัตถุนักเรียนจะมองหาคีย์หลักคลาสที่สอดคล้องกันและเขียนลงในตาราง ดังนั้นข้อมูลในรูปแบบความสัมพันธ์จึงไม่ว่างเปล่าและรหัสที่บันทึกไว้มีดังนี้:
การทดสอบโมฆะสาธารณะ () {เซสชันเซสชัน = null; ลอง {// สร้าง Session Object Session = HiberNateUtils.getSession (); // เปิดเซสชันการทำธุรกรรม BEGINTRANSACTION (); // สร้างวัตถุคลาสและเขียนคลาสคลาสไปยังคลาสฐานข้อมูลคลาส = คลาสใหม่ (); classes.setName ("คลาส"); เซสชัน SAVE (คลาส); // สร้างนักเรียน 1 วัตถุและเขียนวัตถุนักเรียนไปยังนักเรียนฐานข้อมูลนักเรียน 1 = นักเรียนใหม่ (); student1.setName ("จาง"); student1.setClasses (ชั้นเรียน); เซสชัน SAVE (Student1); // สร้างวัตถุนักเรียน 2 วัตถุและเขียนวัตถุนักเรียนไปยังนักเรียนฐานข้อมูลนักเรียน 2 = นักเรียนใหม่ (); student2.setName ("lisi"); student2.setClasses (ชั้นเรียน); เซสชัน SAVE (Student2); session.getTransaction (). commit (); } catch (exception e) {e.printstacktrace (); session.getTransaction (). ย้อนกลับ (); } ในที่สุด {hibernateutils.closesession (เซสชัน); - รายการข้อมูลที่เกี่ยวข้องในฐานข้อมูลการเขียนมีดังนี้:
3.2 เขียนนักเรียนก่อนจากนั้นชั้นเรียน
ก่อนอื่นเขียนนักเรียนลงในฐานข้อมูล ในเวลานี้เนื่องจากตารางนักเรียนจำเป็นต้องได้รับข้อมูลหลักหลักของคอลัมน์คลาสที่สอดคล้องกัน แต่เนื่องจากข้อมูลชั้นเรียนถูกแปลงเป็นสถานะชั่วคราวจะมีค่าว่างเมื่อเขียนข้อมูลนักเรียน รหัสมีดังนี้:
มุมมองฐานข้อมูลที่เกี่ยวข้องหลังจากการเขียนมีดังนี้:
เมื่อเปรียบเทียบการดำเนินการเขียนสองรายการผลลัพธ์ที่แตกต่างกันจะปรากฏขึ้นเนื่องจากคำสั่งของทั้งสองเขียนนั้นแตกต่างกัน แต่เนื่องจากเป็นความสัมพันธ์แบบสองทิศทางจึงไม่มีข้อยกเว้นเกิดขึ้นในระหว่างการเขียน
4. อ่านการดำเนินการ
เมื่อเทียบกับข้อมูลการเขียนข้อมูลการอ่านกลายเป็นเรื่องง่ายมาก เนื่องจากเป็นความสัมพันธ์แบบสองทิศทางการอ่านข้อมูลจึงเป็นแบบสองทิศทาง ข้อมูลจากปลายอีกด้านสามารถอ่านได้จากส่วนท้ายใด ๆ ดังที่แสดงในรหัสต่อไปนี้:
โมฆะสาธารณะ testload1 () {เซสชันเซสชัน = null; ลอง {session = hibernateutils.getSession (); session.beginTransaction (); // อ่านข้อมูลนักเรียนผ่านชั้นเรียนชั้นเรียน = (คลาส) เซสชันโหลด (classes.class, 1); System.out.println ("classes.name ="+classes.getName ()); ตั้งค่านักเรียน = ชั้นเรียน getStudents (); สำหรับ (iterator iter = students.iterator (); iter.hasnext ();) {นักเรียนนักเรียน = (นักเรียน) iter.next (); System.out.println ("student.name ="+student.getName ()); } // อ่านข้อมูลชั้นเรียนผ่านข้อมูลนักเรียนนักเรียน stu = ใหม่นักเรียน (); stu = (นักเรียน) เซสชั่นโหลด (student.class, 1); System.out.println ("ข้อมูลคลาสโหลดผ่านคลาสนักเรียน. id ="+stu.getClasses (). getId ()); session.getTransaction (). commit (); } catch (exception e) {e.printstacktrace (); session.getTransaction (). ย้อนกลับ (); } ในที่สุด {hibernateutils.closesession (เซสชัน); -เรียกใช้คำสั่งการทดสอบข้างต้นและข้อมูลคำสั่งที่เกี่ยวข้องที่สร้างขึ้นมีดังนี้:
Hibernate: เลือก classes0_.id เป็น id1_0_, classes0_.name เป็น name1_0_ จาก t_classes classes0_ โดยที่ classes0_.id =? classes.name = ชั้นเรียน hibernate: เลือกนักเรียน 0_.classesid เป็น classid1_, students0_.id เป็น id1_, นักเรียน 0_.id เป็น id0_0_, นักเรียน 0_.name เป็น name0_0_, นักเรียน 0_.classesid เป็น classid0_0_ จากนักเรียน t_student 0_ Student.Name = Lisi Student.Name = Zhangsan
กำลังโหลดข้อมูลชั้นเรียนโดยชั้นเรียนนักเรียน. id = 1