คำถามนี้เป็นคำถามที่ค่อนข้างที่เกี่ยวข้องกับHibernate หมายเหตุตำแหน่งคำถาม
แต่อยากรู้ว่าอันไหนดีกว่ากัน ? เข้าถึงผ่านคุณสมบัติหรือเข้าถึงผ่านช่อง? ข้อดีข้อเสียของแต่ละอย่างเป็นอย่างไร?
คำถามนี้เป็นคำถามที่ค่อนข้างที่เกี่ยวข้องกับHibernate หมายเหตุตำแหน่งคำถาม
แต่อยากรู้ว่าอันไหนดีกว่ากัน ? เข้าถึงผ่านคุณสมบัติหรือเข้าถึงผ่านช่อง? ข้อดีข้อเสียของแต่ละอย่างเป็นอย่างไร?
คำตอบ:
ฉันชอบ accessors เพราะฉันสามารถเพิ่มตรรกะทางธุรกิจให้กับ accessors ได้ทุกเมื่อที่ต้องการ นี่คือตัวอย่าง:
@Entity
public class Person {
@Column("nickName")
public String getNickName(){
if(this.name != null) return generateFunnyNick(this.name);
else return "John Doe";
}
}
นอกจากนี้หากคุณโยน libs อื่นลงในส่วนผสม (เช่น lib ที่แปลง JSON บางตัวหรือ BeanMapper หรือ Dozer หรือ bean mapping / cloning lib อื่น ๆ ตามคุณสมบัติ getter / setter) คุณจะรับประกันได้ว่า lib นั้นซิงค์กับการคงอยู่ ผู้จัดการ (ทั้งคู่ใช้ getter / setter)
มีข้อโต้แย้งสำหรับทั้งสองอย่าง แต่ส่วนใหญ่เกิดจากข้อกำหนดบางประการของผู้ใช้ "จะเกิดอะไรขึ้นถ้าคุณต้องการเพิ่มตรรกะสำหรับ" หรือ "xxxx break encapsulation" อย่างไรก็ตามไม่มีใครแสดงความคิดเห็นเกี่ยวกับทฤษฎีนี้และให้เหตุผลที่สมเหตุสมผล
Hibernate / JPA กำลังทำอะไรอยู่เมื่อมันยังคงมีวัตถุอยู่นั่นคือสถานะของวัตถุนั้นคงอยู่ นั่นหมายถึงการจัดเก็บในลักษณะที่สามารถทำซ้ำได้ง่าย
การห่อหุ้มคืออะไร? การห่อหุ้มหมายถึงการห่อหุ้มข้อมูล (หรือสถานะ) ด้วยอินเทอร์เฟซที่แอปพลิเคชัน / ไคลเอนต์สามารถใช้เพื่อเข้าถึงข้อมูลได้อย่างปลอดภัย - ทำให้ข้อมูลสอดคล้องและถูกต้อง
คิดว่าสิ่งนี้เหมือนกับ MS Word MS Word คงรูปแบบของเอกสารไว้ในหน่วยความจำ - เอกสาร STATE นำเสนออินเทอร์เฟซที่ผู้ใช้สามารถใช้เพื่อแก้ไขเอกสาร - ชุดปุ่มเครื่องมือคำสั่งแป้นพิมพ์ ฯลฯ อย่างไรก็ตามเมื่อคุณเลือกที่จะคงอยู่ (บันทึก) เอกสารนั้นจะบันทึกสถานะภายในไม่ใช่ชุดของการกดแป้นพิมพ์และ ใช้การคลิกเมาส์เพื่อสร้างมัน
การบันทึกสถานะภายในของวัตถุไม่ทำให้การห่อหุ้ม - มิฉะนั้นคุณจะไม่เข้าใจจริงๆว่าการห่อหุ้มหมายถึงอะไรและเหตุใดจึงมีอยู่ มันเหมือนกับการทำให้เป็นอนุกรมของวัตถุจริงๆ
ด้วยเหตุนี้ในกรณีส่วนใหญ่จึงเหมาะสมที่จะคงอยู่ใน FIELDS ไม่ใช่ ACCESSORS ซึ่งหมายความว่าสามารถสร้างออบเจ็กต์ใหม่จากฐานข้อมูลได้อย่างแม่นยำตรงกับวิธีการจัดเก็บ ไม่จำเป็นต้องมีการตรวจสอบความถูกต้องใด ๆ เนื่องจากสิ่งนี้ทำกับต้นฉบับเมื่อสร้างขึ้นและก่อนที่จะถูกเก็บไว้ในฐานข้อมูล (เว้นแต่พระเจ้าห้ามคุณกำลังจัดเก็บข้อมูลที่ไม่ถูกต้องในฐานข้อมูล !!!!) ในทำนองเดียวกันไม่จำเป็นต้องคำนวณค่าเนื่องจากมีการคำนวณก่อนที่จะจัดเก็บวัตถุ วัตถุควรมีลักษณะเหมือนเดิมก่อนที่จะบันทึก ในความเป็นจริงการเพิ่มสิ่งอื่น ๆ เข้าไปใน getters / setters คุณกำลังเพิ่มความเสี่ยงที่คุณจะสร้างสิ่งที่ไม่ใช่สำเนาต้นฉบับทั้งหมด
แน่นอนว่าฟังก์ชันนี้ถูกเพิ่มเข้ามาด้วยเหตุผล อาจมีบางกรณีการใช้งานที่ถูกต้องสำหรับการคงอยู่กับ accessors อย่างไรก็ตามโดยทั่วไปจะหายาก ตัวอย่างอาจเป็นไปได้ว่าคุณต้องการหลีกเลี่ยงการคงอยู่ของค่าที่คำนวณได้แม้ว่าคุณอาจต้องการถามคำถามว่าทำไมคุณไม่คำนวณตามความต้องการใน getter ของค่าหรือเริ่มต้นด้วยความเกียจคร้านใน getter โดยส่วนตัวแล้วฉันไม่สามารถนึกถึงกรณีการใช้งานที่ดีได้และไม่มีคำตอบใดที่ให้คำตอบ "วิศวกรรมซอฟต์แวร์"
ฉันชอบการเข้าถึงฟิลด์มากกว่าเพราะวิธีนั้นฉันไม่ได้บังคับให้จัดหา getter / setter สำหรับแต่ละคุณสมบัติ
การสำรวจสั้น ๆ ผ่าน Google ชี้ให้เห็นว่าการเข้าถึงข้อมูลเป็นส่วนใหญ่ (เช่นhttp://java.dzone.com/tips/12-feb-jpa-20-why-accesstype )
ฉันเชื่อว่าการเข้าถึงช่องเป็นสำนวนที่ Spring แนะนำ แต่ฉันไม่พบข้อมูลอ้างอิงเพื่อสำรองข้อมูลนั้น
มีคำถาม SO ที่เกี่ยวข้องซึ่งพยายามวัดประสิทธิภาพและได้ข้อสรุปว่า "ไม่มีความแตกต่าง"
นี่คือสถานการณ์ที่คุณต้องใช้ตัวเข้าถึงคุณสมบัติ ลองนึกภาพคุณมีคลาสนามธรรมทั่วไปที่มีความสามารถในการนำไปใช้งานมากมายเพื่อสืบทอดเป็นคลาสย่อยที่เป็นรูปธรรม 8 คลาส:
public abstract class Foo<T extends Bar> {
T oneThing;
T anotherThing;
// getters and setters ommited for brevity
// Lots and lots of implementation regarding oneThing and anotherThing here
}
ตอนนี้คุณควรใส่คำอธิบายประกอบชั้นเรียนนี้อย่างไร? คำตอบคือคุณไม่สามารถใส่คำอธิบายประกอบได้เลยด้วยการเข้าถึงฟิลด์หรือคุณสมบัติเนื่องจากคุณไม่สามารถระบุเอนทิตีเป้าหมายได้ในตอนนี้ คุณต้องใส่คำอธิบายประกอบการใช้งานที่เป็นรูปธรรม แต่เนื่องจากคุณสมบัติที่คงอยู่ถูกประกาศในซูเปอร์คลาสนี้คุณจึงต้องใช้การเข้าถึงคุณสมบัติในคลาสย่อย
การเข้าถึงภาคสนามไม่ใช่ตัวเลือกในแอปพลิเคชันที่มีซูเปอร์คลาสนามธรรมทั่วไป
abstract T getOneThing()
และabstract void setOneThing(T thing)
และใช้การเข้าถึงฟิลด์
ฉันมักจะชอบและใช้ตัวเข้าถึงคุณสมบัติ:
foo.getId()
โดยไม่ต้องเริ่มต้นพร็อกซี (สำคัญเมื่อใช้ไฮเบอร์เนตจนกว่าHHH-3718จะได้รับการแก้ไข)ข้อเสียเปรียบ:
@Transient
นั้นหรือไม่นั่นขึ้นอยู่กับกรณีเฉพาะจริงๆ - ทั้งสองตัวเลือกมีให้สำหรับเหตุผล IMO เดือดถึงสามกรณี:
ฉันขอแนะนำอย่างยิ่งให้การเข้าถึงฟิลด์และไม่ใช่คำอธิบายประกอบบน getters (การเข้าถึงคุณสมบัติ) หากคุณต้องการทำอะไรเพิ่มเติมใน setters มากกว่าแค่การตั้งค่า (เช่นการเข้ารหัสหรือการคำนวณ)
ปัญหาเกี่ยวกับการเข้าถึงคุณสมบัติคือ setters จะถูกเรียกด้วยเมื่อโหลดอ็อบเจ็กต์ สิ่งนี้ได้ผลดีสำหรับฉันเป็นเวลาหลายเดือนจนกระทั่งเราต้องการแนะนำการเข้ารหัส ในกรณีการใช้งานของเราเราต้องการเข้ารหัสฟิลด์ใน setter และถอดรหัสใน getter ตอนนี้ปัญหาเกี่ยวกับการเข้าถึงคุณสมบัติคือเมื่อ Hibernate โหลดอ็อบเจ็กต์มันก็กำลังเรียก setter เพื่อเติมข้อมูลในฟิลด์และกำลังเข้ารหัสค่าที่เข้ารหัสอีกครั้ง โพสต์นี้ยังกล่าวถึงสิ่งนี้ด้วย: Java Hibernate: ลักษณะการทำงานของชุดคุณสมบัติที่แตกต่างกันขึ้นอยู่กับว่าใครเรียกมัน
สิ่งนี้ทำให้ฉันปวดหัวจนจำความแตกต่างระหว่างการเข้าถึงข้อมูลและการเข้าถึงทรัพย์สินได้ ตอนนี้ฉันได้ย้ายคำอธิบายประกอบทั้งหมดของฉันจากการเข้าถึงคุณสมบัติไปสู่การเข้าถึงฟิลด์และตอนนี้ก็ใช้งานได้ดี
ฉันชอบใช้การเข้าถึงช่องด้วยเหตุผลต่อไปนี้:
การเข้าถึงคุณสมบัติอาจนำไปสู่ข้อบกพร่องที่น่ารังเกียจเมื่อใช้ equals / hashCode และการอ้างอิงฟิลด์โดยตรง (ซึ่งตรงข้ามกับ getters) เนื่องจากพร็อกซีจะเริ่มต้นเมื่อเข้าถึง getters เท่านั้นและการเข้าถึงโดยตรงในฟิลด์จะคืนค่า null
เข้าถึงสถานที่ให้บริการคุณจะต้องใส่คำอธิบายประกอบทุกวิธียูทิลิตี้ (เช่น addChild / RemoveChild) @Transient
เช่น
ด้วยการเข้าถึงฟิลด์เราสามารถซ่อนฟิลด์ @Version ได้โดยไม่เปิดเผย getter เลย ผู้เริ่มต้นสามารถนำไปสู่การเพิ่มตัวตั้งค่าได้เช่นกันและversion
ไม่ควรตั้งค่าฟิลด์ด้วยตนเอง (ซึ่งอาจนำไปสู่ปัญหาที่น่ารังเกียจได้) การเพิ่มเวอร์ชันทั้งหมดควรทริกเกอร์ผ่านOPTIMISTIC_FORCE_INCREMENTหรือPESSIMISTIC_FORCE_INCREMENT การล็อกแบบชัดแจ้ง
version
ฟิลด์มักมีประโยชน์ในสถานการณ์ที่ใช้ DTO แทนเอนทิตีแยก
ให้ฉันพยายามสรุปเหตุผลที่สำคัญที่สุดในการเลือกการเข้าถึงตามฟิลด์ หากคุณต้องการเจาะลึกมากขึ้นโปรดอ่านบทความนี้ในบล็อกของฉัน: กลยุทธ์การเข้าถึงใน JPA และ Hibernate - การเข้าถึงฟิลด์หรือคุณสมบัติใดดีกว่ากัน
การเข้าถึงตามฟิลด์เป็นตัวเลือกที่ดีกว่า นี่คือ 5 เหตุผลสำหรับมัน:
เหตุผลที่ 1: อ่านโค้ดได้ดีขึ้น
หากคุณใช้การเข้าถึงตามฟิลด์คุณสามารถใส่คำอธิบายประกอบแอตทริบิวต์เอนทิตีของคุณด้วยคำอธิบายประกอบการแมปของคุณ การวางคำจำกัดความของแอตทริบิวต์เอนทิตีทั้งหมดไว้ที่ด้านบนสุดของคลาสคุณจะได้มุมมองที่ค่อนข้างกะทัดรัดของแอตทริบิวต์ทั้งหมดและการแมป
เหตุผลที่ 2: ละเว้นเมธอด getter หรือ setter ที่แอปพลิเคชันของคุณไม่ควรเรียก
ข้อดีอีกอย่างของการเข้าถึงตามฟิลด์คือผู้ให้บริการการคงอยู่ของคุณเช่น Hibernate หรือ EclipseLink ไม่ได้ใช้เมธอด getter และ setter ของแอตทริบิวต์เอนทิตีของคุณ นั่นหมายความว่าคุณไม่จำเป็นต้องระบุวิธีการใด ๆ ที่ไม่ควรใช้กับรหัสธุรกิจของคุณ ส่วนใหญ่มักเป็นกรณีของเมธอด setter ของแอตทริบิวต์คีย์หลักที่สร้างขึ้นหรือคอลัมน์เวอร์ชัน ผู้ให้บริการคงอยู่ของคุณจะจัดการค่าของแอตทริบิวต์เหล่านี้และคุณไม่ควรตั้งค่าโดยใช้โปรแกรม
เหตุผลที่ 3: การใช้วิธี getter และ setter ที่ยืดหยุ่น
เนื่องจากผู้ให้บริการการคงอยู่ของคุณไม่ได้เรียกใช้วิธี getter และ setter พวกเขาจึงไม่ถูกบังคับให้ปฏิบัติตามข้อกำหนดภายนอกใด ๆ คุณสามารถใช้วิธีการเหล่านี้ในแบบที่คุณต้องการ ซึ่งช่วยให้คุณสามารถใช้กฎการตรวจสอบความถูกต้องเฉพาะธุรกิจทริกเกอร์ตรรกะทางธุรกิจเพิ่มเติมหรือแปลงแอตทริบิวต์เอนทิตีเป็นประเภทข้อมูลอื่น
คุณสามารถยกตัวอย่างเช่นการใช้งานที่ห่อสมาคมเสริมหรือแอตทริบิวต์เป็น Optional
Java
เหตุผลที่ 4: ไม่จำเป็นต้องทำเครื่องหมายวิธียูทิลิตี้เป็น @Transient
@Transient
ประโยชน์ของกลยุทธ์การเข้าถึงข้อมูลที่ใช้ก็คือการที่คุณไม่จำเป็นต้องอธิบายวิธีการสาธารณูปโภคของคุณด้วย คำอธิบายประกอบนี้บอกผู้ให้บริการคงอยู่ของคุณว่าเมธอดหรือแอตทริบิวต์ไม่ได้เป็นส่วนหนึ่งของสถานะคงอยู่ของเอนทิตี และเนื่องจากด้วยการเข้าถึงประเภทฟิลด์สถานะถาวรจะถูกกำหนดโดยแอตทริบิวต์ของเอนทิตีของคุณการใช้งาน JPA ของคุณจึงไม่สนใจวิธีการทั้งหมดของเอนทิตีของคุณ
เหตุผลที่ 5: หลีกเลี่ยงข้อบกพร่องเมื่อทำงานกับพร็อกซี
ไฮเบอร์เนตใช้พร็อกซีสำหรับการเชื่อมโยงกับหนึ่งที่ดึงมาอย่างเฉื่อยชาเพื่อให้สามารถควบคุมการเริ่มต้นของการเชื่อมโยงเหล่านี้ได้ แนวทางนั้นใช้ได้ดีในเกือบทุกสถานการณ์ แต่จะทำให้เกิดข้อผิดพลาดที่เป็นอันตรายหากคุณใช้การเข้าถึงตามคุณสมบัติ
หากคุณใช้การเข้าถึงตามคุณสมบัติไฮเบอร์เนตจะเริ่มต้นแอ็ตทริบิวต์ของวัตถุพร็อกซีเมื่อคุณเรียกใช้เมธอด getter ในกรณีนี้เสมอหากคุณใช้วัตถุพร็อกซีในรหัสธุรกิจของคุณ แต่การใช้งานequals และ hashCodeค่อนข้างมากจะเข้าถึงแอตทริบิวต์โดยตรง หากนี่เป็นครั้งแรกที่คุณเข้าถึงแอตทริบิวต์พร็อกซีแอตทริบิวต์เหล่านี้จะยังไม่ได้กำหนดค่าเริ่มต้น
ฉันคิดว่าการใส่คำอธิบายประกอบพร็อพเพอร์ตี้นั้นดีกว่าเนื่องจากการอัปเดตฟิลด์จะทำให้การห่อหุ้มไม่ได้โดยตรงแม้ว่า ORM ของคุณจะทำ
นี่เป็นตัวอย่างที่ดีว่าจะทำให้คุณไหม้ได้ที่ไหน: คุณอาจต้องการคำอธิบายประกอบสำหรับตัวตรวจสอบไฮเบอร์เนตและความคงอยู่ในที่เดียวกัน (ไม่ว่าจะเป็นฟิลด์หรือคุณสมบัติ) หากคุณต้องการทดสอบการตรวจสอบความถูกต้องไฮเบอร์เนตของคุณซึ่งมีคำอธิบายประกอบอยู่ในฟิลด์คุณไม่สามารถใช้การเยาะเย้ยเอนทิตีของคุณเพื่อแยกการทดสอบหน่วยของคุณเป็นเพียงเครื่องมือตรวจสอบความถูกต้อง อุ๊ย.
ฉันเชื่อว่าการเข้าถึงพร็อพเพอร์ตี้กับการเข้าถึงฟิลด์นั้นแตกต่างกันอย่างมากเมื่อเทียบกับการเริ่มต้นแบบขี้เกียจ
พิจารณาการแมปต่อไปนี้สำหรับถั่วพื้นฐาน 2 ชนิด:
<hibernate-mapping package="org.nkl.model" default-access="field">
<class name="FieldBean" table="FIELD_BEAN">
<id name="id">
<generator class="sequence" />
</id>
<property name="message" />
</class>
</hibernate-mapping>
<hibernate-mapping package="org.nkl.model" default-access="property">
<class name="PropBean" table="PROP_BEAN">
<id name="id">
<generator class="sequence" />
</id>
<property name="message" />
</class>
</hibernate-mapping>
และการทดสอบหน่วยต่อไปนี้:
@Test
public void testFieldBean() {
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
FieldBean fb = new FieldBean("field");
Long id = (Long) session.save(fb);
tx.commit();
session.close();
session = sessionFactory.openSession();
tx = session.beginTransaction();
fb = (FieldBean) session.load(FieldBean.class, id);
System.out.println(fb.getId());
tx.commit();
session.close();
}
@Test
public void testPropBean() {
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
PropBean pb = new PropBean("prop");
Long id = (Long) session.save(pb);
tx.commit();
session.close();
session = sessionFactory.openSession();
tx = session.beginTransaction();
pb = (PropBean) session.load(PropBean.class, id);
System.out.println(pb.getId());
tx.commit();
session.close();
}
คุณจะเห็นความแตกต่างเล็กน้อยในการเลือกที่ต้องการ:
Hibernate:
call next value for hibernate_sequence
Hibernate:
insert
into
FIELD_BEAN
(message, id)
values
(?, ?)
Hibernate:
select
fieldbean0_.id as id1_0_,
fieldbean0_.message as message1_0_
from
FIELD_BEAN fieldbean0_
where
fieldbean0_.id=?
0
Hibernate:
call next value for hibernate_sequence
Hibernate:
insert
into
PROP_BEAN
(message, id)
values
(?, ?)
1
นั่นคือการโทรfb.getId()
ต้องมีการเลือกในขณะที่pb.getId()
ไม่ได้
โดยค่าเริ่มต้นผู้ให้บริการ JPA จะเข้าถึงค่าของฟิลด์เอนทิตีและแม็พฟิลด์เหล่านั้นกับคอลัมน์ฐานข้อมูลโดยใช้วิธีการเข้าถึงคุณสมบัติ JavaBean (getter) และ mutator (setter) ของเอนทิตี ด้วยเหตุนี้ชื่อและประเภทของฟิลด์ส่วนตัวในเอนทิตีจึงไม่สำคัญกับ JPA แต่ JPA จะดูเฉพาะชื่อและประเภทการส่งคืนของตัวเข้าถึงคุณสมบัติ JavaBean คุณสามารถแก้ไขสิ่งนี้ได้โดยใช้@javax.persistence.Access
คำอธิบายประกอบซึ่งช่วยให้คุณระบุวิธีการเข้าถึงอย่างชัดเจนที่ผู้ให้บริการ JPA ควรใช้
@Entity
@Access(AccessType.FIELD)
public class SomeEntity implements Serializable
{
...
}
ตัวเลือกที่ใช้ได้สำหรับ AccessType enum คือ PROPERTY (ค่าเริ่มต้น) และ FIELD ด้วย PROPERTY ผู้ให้บริการรับและตั้งค่าฟิลด์โดยใช้วิธีคุณสมบัติ JavaBean FIELD ทำให้ผู้ให้บริการรับและตั้งค่าฟิลด์โดยใช้ฟิลด์อินสแตนซ์ ตามแนวทางปฏิบัติที่ดีที่สุดคุณควรยึดติดกับค่าเริ่มต้นและใช้คุณสมบัติ JavaBean เว้นแต่คุณจะมีเหตุผลที่น่าสนใจที่จะทำอย่างอื่น
คุณสามารถใส่คำอธิบายประกอบคุณสมบัติเหล่านี้ในฟิลด์ส่วนตัวหรือวิธีการเข้าถึงสาธารณะ หากคุณใช้AccessType.PROPERTY
(ค่าเริ่มต้น) และใส่คำอธิบายประกอบฟิลด์ส่วนตัวแทนตัวเข้าถึง JavaBean ชื่อฟิลด์ต้องตรงกับชื่อคุณสมบัติ JavaBean อย่างไรก็ตามชื่อไม่จำเป็นต้องตรงกันหากคุณใส่คำอธิบายประกอบตัวเข้าถึง JavaBean ในทำนองเดียวกันหากคุณใช้AccessType.FIELD
และใส่คำอธิบายประกอบตัวเข้าถึง JavaBean แทนฟิลด์ชื่อฟิลด์ต้องตรงกับชื่อคุณสมบัติ JavaBean ด้วย ในกรณีนี้พวกเขาไม่จำเป็นต้องจับคู่หากคุณใส่คำอธิบายประกอบในช่อง มันเป็นเรื่องที่ดีที่สุดที่จะเพียงแค่มีความสอดคล้องและอธิบาย accessors JavaBean สำหรับและฟิลด์สำหรับAccessType.PROPERTY
AccessType.FIELD
สิ่งสำคัญคือคุณไม่ควรผสมคำอธิบายประกอบคุณสมบัติ JPA และคำอธิบายประกอบฟิลด์ JPA ในเอนทิตีเดียวกัน การทำเช่นนี้ส่งผลให้เกิดพฤติกรรมที่ไม่ระบุรายละเอียดและมีแนวโน้มที่จะทำให้เกิดข้อผิดพลาด
นั่นเป็นการนำเสนอแบบเก่า แต่ Rod แนะนำว่าคำอธิบายประกอบเกี่ยวกับการเข้าถึงพร็อพเพอร์ตี้สนับสนุนโมเดลโดเมนที่เป็นโรคโลหิตจางและไม่ควรเป็นวิธี "เริ่มต้น" ในการใส่คำอธิบายประกอบ
อีกจุดหนึ่งที่สนับสนุนการเข้าถึงภาคสนามคือมิฉะนั้นคุณจะถูกบังคับให้เปิดเผยตัวตั้งค่าสำหรับคอลเลกชันเช่นกันสิ่งที่เป็นความคิดที่ไม่ดีสำหรับฉันเนื่องจากการเปลี่ยนอินสแตนซ์คอลเลกชันถาวรเป็นวัตถุที่ไม่ได้รับการจัดการโดย Hibernate จะทำลายความสอดคล้องของข้อมูลของคุณอย่างแน่นอน
ดังนั้นฉันชอบที่จะมีคอลเลกชันเป็นฟิลด์ที่ได้รับการป้องกันซึ่งเริ่มต้นเพื่อการใช้งานที่ว่างเปล่าในตัวสร้างเริ่มต้นและแสดงเฉพาะ getters ของพวกเขา จากนั้นการดำเนินงานการจัดการเพียงชอบclear()
, remove()
, removeAll()
ฯลฯ เป็นไปได้ว่าจะไม่ทำให้ Hibernate ไม่รู้ของการเปลี่ยนแปลง
ฉันชอบฟิลด์มากกว่า แต่ฉันเจอสถานการณ์หนึ่งที่ดูเหมือนจะบังคับให้ฉันต้องวางคำอธิบายประกอบบน getters
ด้วยการใช้งาน Hibernate JPA @Embedded
ดูเหมือนจะไม่ทำงานในฟิลด์ ดังนั้นจึงต้องดำเนินการต่อไป และเมื่อคุณใส่สิ่งนั้นลงบน getter แล้ว@Column
คำอธิบายประกอบต่างๆก็ต้องไปอยู่บนgetter ด้วย (ฉันคิดว่า Hibernate ไม่ต้องการสนามผสมและตัวรับที่นี่) และเมื่อคุณใส่@Column
getters ในคลาสเดียวแล้วมันก็สมเหตุสมผลที่จะทำเช่นนั้นตลอดไป
ฉันชอบผู้เข้าถึงฟิลด์ โค้ดจะสะอาดกว่ามาก คำอธิบายประกอบทั้งหมดสามารถวางไว้ในส่วนเดียวของชั้นเรียนและรหัสจะอ่านง่ายกว่ามาก
ฉันพบปัญหาอื่นกับตัวเข้าถึงคุณสมบัติ: ถ้าคุณมีเมธอด getXYZ ในคลาสของคุณที่ไม่ได้ใส่คำอธิบายประกอบว่าเกี่ยวข้องกับคุณสมบัติถาวรไฮเบอร์เนตจะสร้าง sql เพื่อพยายามรับคุณสมบัติเหล่านั้นส่งผลให้เกิดข้อความแสดงข้อผิดพลาดที่สับสนมาก เสียเวลาไปสองชั่วโมง ฉันไม่ได้เขียนรหัสนี้ ที่ผ่านมาฉันใช้ตัวเข้าถึงฟิลด์มาโดยตลอดและไม่เคยพบปัญหานี้
เวอร์ชันไฮเบอร์เนตที่ใช้ในแอพนี้:
<!-- hibernate -->
<hibernate-core.version>3.3.2.GA</hibernate-core.version>
<hibernate-annotations.version>3.4.0.GA</hibernate-annotations.version>
<hibernate-commons-annotations.version>3.1.0.GA</hibernate-commons-annotations.version>
<hibernate-entitymanager.version>3.4.0.GA</hibernate-entitymanager.version>
คุณควรเลือกการเข้าถึงผ่านฟิลด์มากกว่าการเข้าถึงผ่านคุณสมบัติ ด้วยช่องคุณสามารถ จำกัด ข้อมูลที่ส่งและรับได้ ด้วยคุณสมบัติคุณสามารถส่งข้อมูลได้มากขึ้นในฐานะโฮสต์และตั้งค่านิกาย G (ซึ่งโรงงานตั้งค่าคุณสมบัติส่วนใหญ่ทั้งหมด)
ฉันได้แก้ไขการเริ่มต้นที่ขี้เกียจและการเข้าถึงฟิลด์ที่นี่ไฮเบอร์เนตหนึ่งต่อหนึ่ง: getId () โดยไม่ต้องดึงวัตถุทั้งหมด
เราสร้างเอนทิตี bean และใช้คำอธิบายประกอบ getter ปัญหาที่เราพบคือเอนทิตีบางรายการมีกฎที่ซับซ้อนสำหรับคุณสมบัติบางอย่างเกี่ยวกับเวลาที่สามารถอัปเดตได้ วิธีแก้ปัญหาคือต้องมีตรรกะทางธุรกิจบางอย่างในตัวเซ็ตเตอร์แต่ละตัวที่กำหนดว่าค่าจริงเปลี่ยนแปลงหรือไม่และถ้าเป็นเช่นนั้นควรอนุญาตให้เปลี่ยนแปลงหรือไม่ แน่นอนว่าไฮเบอร์เนตสามารถตั้งค่าคุณสมบัติได้เสมอดังนั้นเราจึงลงเอยด้วยเซ็ตเตอร์สองกลุ่ม ค่อนข้างน่าเกลียด.
เมื่ออ่านโพสต์ก่อนหน้านี้ฉันยังเห็นว่าการอ้างอิงคุณสมบัติจากภายในเอนทิตีอาจทำให้เกิดปัญหากับคอลเลกชันที่ไม่โหลด
สิ่งที่สำคัญที่สุดคือฉันจะเอนเอียงไปที่การใส่คำอธิบายประกอบฟิลด์ในอนาคต
โดยปกติถั่วเป็น POJO ดังนั้นพวกเขาจึงมี accessors อยู่แล้ว
ดังนั้นคำถามจึงไม่ใช่ "อันไหนดีกว่า" แต่เป็นเพียง "เมื่อใดจึงจะใช้การเข้าถึงภาคสนาม" และคำตอบก็คือ "เมื่อคุณไม่ต้องการตัวตั้งรับ / ผู้ลงสนาม!"
ฉันคิดถึงสิ่งนี้และฉันเลือกวิธีการเข้าถึง
ทำไม?
เนื่องจากฟิลด์และแอคเซสซอร์เมทเหมือนกัน แต่ถ้าในภายหลังฉันต้องการตรรกะบางอย่างในฟิลด์โหลดฉันบันทึกการย้ายคำอธิบายประกอบทั้งหมดที่วางในฟิลด์
ความนับถือ
กรูฮาร์ต
เพื่อให้ชั้นเรียนของคุณสะอาดขึ้นให้ใส่คำอธิบายประกอบลงในช่องจากนั้นใช้ @Access (AccessType.PROPERTY)
ทั้งสอง:
ข้อมูลจำเพาะ EJB3 กำหนดให้คุณต้องประกาศคำอธิบายประกอบเกี่ยวกับชนิดองค์ประกอบที่จะเข้าถึงเช่นเมธอด getter หากคุณใช้การเข้าถึงคุณสมบัติฟิลด์ถ้าคุณใช้การเข้าถึงฟิลด์
https://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/#entity-mapping
AccessType.PROPERTY: การใช้งานความคงอยู่ของ EJB จะโหลดสถานะในคลาสของคุณผ่านเมธอด "setter" ของ JavaBean และดึงสถานะจากคลาสของคุณโดยใช้เมธอด JavaBean "getter" นี่คือค่าเริ่มต้น
AccessType.FIELD: สถานะถูกโหลดและดึงข้อมูลโดยตรงจากฟิลด์คลาสของคุณ คุณไม่จำเป็นต้องเขียน JavaBean "getters" และ "setters"