3.1 บทนำ
สิ่งที่มีประโยชน์อีกอย่าง ที่ฉันอยากจะพูดถึงคือNativeQuery ดังที่คุณทราบแล้ว การใช้ NativeQuery คุณสามารถเขียนข้อความค้นหาใน SQL แบบเนทีฟได้ อย่างไรก็ตาม สิ่งที่น่าสนใจยิ่งกว่าคือ คุณไม่จำเป็นต้องใช้การแมปคลาสเมื่อได้รับผลลัพธ์คิวรี
ฉันจะแสดงให้คุณเห็นตัวอย่าง:
List<Object[]> persons = session.createNativeQuery("SELECT * FROM Person").list();
ในตัวอย่างนี้ เราจะไม่ผ่านคลาสที่ตรงกับแถวผลลัพธ์ของคิวรี แต่เราใช้อาร์เรย์ของออบเจกต์แทน
สิ่งนี้มีประโยชน์หากคุณต้องการเลือกเพียงไม่กี่คอลัมน์ในตาราง ตัวอย่าง:
List<Object[]> persons = session.createNativeQuery("SELECT id, name FROM Person").list();
for(Object[] person : persons) {
Number id = (Number) person[0];
String name = (String) person[1];
}
สิ่งนี้ค่อนข้างคล้ายกับแนวทาง JDBC เมื่อคุณได้รับวัตถุ ResultSet และอ่านข้อมูลจากแถวของมัน
อย่างไรก็ตาม Hibernate เสนอวิธีต่างๆ เพื่อทำให้สิ่งนี้น่าเชื่อถือมากขึ้น ตัวอย่างเช่น คุณสามารถระบุประเภทของคอลัมน์ที่คุณต้องการลบ ตัวอย่าง:
Query<Object[]> query = session.createNativeQuery("SELECT id, name FROM Person");
query.addScalar("id", StandardBasicTypes.LONG);
query.addScalar("name", StandardBasicTypes.STRING);
List<Object[]> persons = query.list();
for(Object[] person : persons) {
Long id = (Long) person[0];
String name = (String) person[1];
}
3.2 การแมปเอนทิตี
คุณยังสามารถระบุคลาสที่ Hibernate ควรใช้อย่างชัดเจนเมื่อแยกวิเคราะห์ผลลัพธ์ของNativeQuery สามารถทำได้หลายวิธี
Query<Person> query = session.createNativeQuery("SELECT * FROM Person")
.addEntity(Person.class);
.list();
และแน่นอน รูปแบบเก่าที่ดีที่คุณรู้จัก:
Query<Person> query = session.createNativeQuery("SELECT * FROM Person", Person.class).list();
วิธีแรกคือวิธี Hibernate ดั้งเดิม และวิธีที่สองคือวิธี JPA วิธีการของ JPA นั้นสะดวกและรัดกุมกว่า เนื่องจากมาตรฐานนี้ถูกคิดค้นขึ้นหลังจากที่ Hibernate มีอยู่เป็นเวลาหลายปี และไฮเบอร์เนตก็พัฒนาและถูกบังคับให้สนับสนุนแนวทางเก่าเพื่อรักษาความเข้ากันได้กับเวอร์ชันเก่า
ยังไงก็ตาม ด้วยแนวทางของมัน Hibernate ช่วยให้คุณไม่เชื่อมต่อคลาสเดียวกับการแมปผลลัพธ์ของคิวรี แต่มีหลายคลาส ตัวอย่าง:
List<Phone> results = session.createNativeQuery(
"SELECT {ph.*}, {pr.*}" +
"FROM Phone ph" +
"JOIN Person pr ON ph.person_id = pr.id")
.addEntity("ph", Phone.class)
.addJoin("pr", "ph.person")
.list();
for (Phone. phone : results) {
assertNotNull( phone.getPerson().getName() );
}
สามารถใช้วิธีการนี้โดยใช้NativeQuery เพื่อเพิ่มความเร็วในการเลือกข้อมูลจากฐานข้อมูล หากคุณทราบว่าไม่ต้องการบางคอลัมน์ คุณสามารถเว้นไว้ในคำขอได้
คุณยังสามารถโหลดเอน ทิตีย่อยทั้งหมดในคราวเดียว แม้ว่าไฮเบอร์เนตต้องการใช้แคชหรือ กลไก LazyLoading นอกจากนี้ เอนทิตีย่อยของคุณอาจมีหลายคอลัมน์ในฐานข้อมูล และคุณสามารถเลือกได้เพียงบางคอลัมน์เท่านั้น
3.3 การทำแผนที่ DTO
ไฮเบอร์เนตยังอนุญาตให้คุณใช้คลาสที่ไม่ใช่เอนทิตีเพื่อแมปผลลัพธ์ คลาสที่ไม่มีคำอธิบายประกอบและไม่ได้แมปกับตารางใดๆ
ตัวอย่าง:
public class PersonSummaryDTO {
private Number id;
private String name;
public Number getId() {
return id;
}
public void setId(Number id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
List<PersonSummaryDTO> dtos = session.createNativeQuery(
"SELECT p.id as \"id\", p.name as \"name\" FROM Person p")
.setResultTransformer(Transformers.aliasToBean(PersonSummaryDTO.class) )
.list();
เนื่องจากไม่มีคำอธิบายประกอบในคลาส PersonSummaryDTO ชื่อของคอลัมน์ในแบบสอบถาม SQL จะต้องตรงกับชื่อฟิลด์ของคลาส PersonSummaryDTO ทุกประการ
สิ่งนี้มีประโยชน์มากหากคุณกำลังอ่านข้อมูลจากฐานข้อมูลภายนอกที่แอปพลิเคชันของคุณเชื่อมต่อในโหมดอ่านอย่างเดียวเท่านั้น นั่นคือ คุณได้รับสิทธิ์เข้าถึงตารางที่มีมากกว่า 50 คอลัมน์ ซึ่งเก็บข้อมูลไว้ในรูปแบบที่ไม่ปกติเพื่อเพิ่มความเร็วในการเลือก
หรือสมมติว่ามีคนตัดสินใจจัดเก็บลำดับชั้นของชั้นเรียนไว้ในตารางเดียว และในห้าปีตารางนี้ก็เติบโตขึ้นมากจนปีศาจจะหักขาของเขา คุณต้องเลือกสองสามคอลัมน์จากตารางนี้ (รหัสและชื่อผู้ใช้) และมอบให้กับลูกค้า
ฉันคิดว่าคุณเข้าใจ แต่ถ้าคุณต้องการเจาะลึกในหัวข้อนี้ คุณสามารถอ่านเพิ่มเติมได้ที่ลิงค์:
GO TO FULL VERSION