ในบทความ "Strong Delphi Rtti - การอภิปรายเกี่ยวกับความต้องการที่จะเข้าใจภาษาการพัฒนาหลายภาษา" ฉันบอกว่าฉันใช้ RTTI ของ Delphi เพื่อใช้การคัดค้านชุดข้อมูลอย่างง่าย บทความนี้จะแนะนำวิธีการใช้งานของฉันโดยละเอียด
เริ่มต้นด้วยตัวอย่างง่ายๆ: สมมติว่ามีการควบคุม Adodataset ที่เชื่อมต่อกับฐานข้อมูล Roswen และ SQL คือ:
เลือก * จากพนักงาน
ตอนนี้คุณต้องแสดงฟิลด์สี่ฟิลด์ EmployeeId, FirstName, LastName และ Birthdate ในเนื้อหาลงใน ListView รหัสดั้งเดิมมีดังนี้:
ด้วย adodataset1 เริ่มเปิด; FieldByName ('LastName') .STRING);มีปัญหาหลักหลายประการที่นี่:
1. ก่อนอื่นมีรหัสจำนวนมากที่มีคำย้ำมาก ตัวอย่างเช่น FieldByName และ ASXXX ฯลฯ โดยเฉพาะอย่างยิ่ง ASXXX คุณต้องจำไว้เสมอว่าประเภทของแต่ละฟิลด์คืออะไรซึ่งง่ายต่อการทำผิดพลาด ยิ่งกว่านั้นหากไม่สามารถแปลงประเภทที่เข้ากันไม่ได้บางประเภทจะไม่พบข้อผิดพลาดจนกว่าจะถึงเวลาทำงาน
2. คุณต้องประมวลผลการเคลื่อนไหวของบันทึกปัจจุบันในลูปด้วยตัวคุณเอง เช่นเดียวกับข้างต้นมิฉะนั้นลูปที่ตายแล้วจะเกิดขึ้นเมื่อคุณลืมมัน
3. สิ่งที่สำคัญที่สุดคือชื่อฟิลด์จะถูกส่งผ่านพารามิเตอร์สตริง FieldByName มีแนวโน้มที่จะทำให้ปัญหาดังกล่าวจะปรากฏขึ้นหากลูกค้าล่าช้า ชื่อฟิลด์ผิดประเภทนี้ง่ายต่อการเกิดขึ้นโดยเฉพาะอย่างยิ่งเมื่อโปรแกรมใช้หลายตารางมันเป็นเรื่องง่ายที่จะสร้างความสับสนให้กับชื่อฟิลด์ของตารางที่แตกต่างกัน
ในยุคนี้ปกครองโดย OO เมื่อเราพบการดำเนินการที่เกี่ยวข้องกับชุดข้อมูลเรายังคงต้องตกอยู่ในรายละเอียดของฐานข้อมูลเชิงสัมพันธ์ที่กล่าวถึงข้างต้น แน่นอนว่ายังมีวิธีกำจัดพวกเขาในขณะนี้นั่นคือการแมป O/R แต่การทำแผนที่ O/R นั้นแตกต่างจากวิธีการพัฒนาแบบดั้งเดิมมากเกินไปโดยเฉพาะอย่างยิ่งสำหรับแอปพลิเคชันขนาดเล็กบางอย่างไม่จำเป็นต้องพูดเกินจริง มัน
แรงบันดาลใจจาก Java และภาษาไดนามิกอื่น ๆ ฉันคิดว่าจะใช้ RTTI ที่ทรงพลังของ Delphi เพื่อใช้รูปแบบการคัดค้านชุดข้อมูลอย่างง่ายนี้ ต่อไปนี้เป็นรหัสแอปพลิเคชันที่คัดค้านชุดข้อมูลที่ใช้ฟังก์ชั่นเดียวกันกับรหัสดั้งเดิม:
พิมพ์ TDSPEMPOLYEE = คลาส (TMDATASETPROXY) ที่เผยแพร่คุณสมบัติ EmployeeId: Integer Index 0 อ่าน Getinteger Write Setinteger; Setvariant; end; ขั้นตอน tform1.listclick (ผู้ส่ง: tobject); var emp: tdspemployee; (Emp.EmployeeId); Emp.free;
การใช้งานง่ายมาก สิ่งที่สำคัญที่สุดคือการกำหนดคลาสพร็อกซีก่อนซึ่งใช้แอตทริบิวต์ที่เผยแพร่เพื่อกำหนดฟิลด์ทั้งหมดรวมถึงประเภทของพวกเขาจากนั้นคุณสามารถจัดการกับชุดข้อมูลในลักษณะวัตถุ คลาสพร็อกซีนี้ได้มาจาก TMDatasetProxy ซึ่งใช้ RTTI เพื่อใช้การแมปจากการดำเนินการแอตทริบิวต์ไปยังการดำเนินงานภาคสนาม หน่วยการใช้งานของคลาสนี้จะอธิบายอย่างละเอียดด้านล่าง
บนพื้นผิวมีคลาสพร็อกซีพิเศษที่กำหนดชุดข้อมูลซึ่งดูเหมือนว่าจะมีรหัสมากขึ้น แต่นี่เป็นสิ่งเดียวโดยเฉพาะอย่างยิ่งเมื่อโปรแกรมจำเป็นต้องนำโครงสร้างข้อมูลใหม่มาใช้ซ้ำหลายครั้งรหัส จะทำ ยิ่งไปกว่านั้นคำจำกัดความของคลาสพร็อกซีนี้นั้นง่ายมาก ฟังก์ชั่นการเข้าถึงแอตทริบิวต์ getxxx/setxxx ที่ใช้ทั้งหมดถูกนำไปใช้ในคลาสฐาน tmdatasetproxy
ทีนี้มาดูลูปที่สอดคล้องกับรหัสต้นฉบับ:
1. ไม่จำเป็นต้องใช้ FieldByName และ ASXXX และพวกเขาได้กลายเป็นแอตทริบิวต์ในคลาสพร็อกซี มัน หากใช้ประเภทผิดจะมีการรายงานข้อผิดพลาดระหว่างการรวบรวม
2. ใช้ foreach เพื่อทำการสำรวจการสำรวจและไม่ต้องกังวลเกี่ยวกับการลืมวนซ้ำที่เกิดจากถัดไป
3. ข้อได้เปรียบที่ใหญ่ที่สุดคือชื่อฟิลด์กลายเป็นคุณสมบัติดังนั้นคุณสามารถเพลิดเพลินไปกับประโยชน์ของการตรวจสอบชื่อฟิลด์ในเวลาที่รวบรวม
ตอนนี้เริ่มพูดคุย TMDatasetProxy รหัสของการใช้งานมีดังนี้:
(*********************************************************** ******************** ชุดข้อมูลพร็อกซีที่ใช้กับ RTTI สามารถคัดค้านชุดข้อมูลได้วันที่: ม.ค. 28-05 *************************************** ********************) หน่วย MDSPCOMM; interfaceuses classes, db, typinfo; พิมพ์ tmproplist = คลาส (tobject) private fpropcount: integer; (Aindex: Integer): ShortString; อุปกรณ์ประกอบฉาก [ANDEX: Integer]: ppropinfo อ่าน getprop; ฟังก์ชั่นเสมือนจริง; Setfloat ขั้นตอน; TDATASET) การทำลายล้าง; classinfo)^. propcount; (fproplist) จากนั้น freemem (fproplist); tmproplist.getPropname (aindex: จำนวนเต็ม): shortstring; เริ่มต้นผล: = getProp (aindex)^. name; end; {tmrefdataset} constructor tmdatasetproxy.create การลอยตัว: = เท็จ; สิ้นสุด; ขั้นตอน tmdatasetproxy.beginedit; เริ่มต้นถ้า (fdataset.state <> dsedit) และ (fdataset.state <> dsinsert) จากนั้น fdataset.edit; end; ขั้นตอน tmdatasetproxy.ended; . state = dsinsert) จากนั้น fdataset.post; end; ฟังก์ชั่น tmdatasetproxy.getinteger (Aindex: จำนวนเต็ม): จำนวนเต็ม; : จำนวนเต็ม): double; เริ่มต้นผลลัพธ์: = fdataset.fieldbyname (fproplist.propnames [aindex]) .asfloat; end; ฟังก์ชั่น tmdatasetproxy.getString (aindex: integer): สตริง; เริ่มต้นผลลัพธ์: = fdataset.fieldbyname aindex]) .asstring; end; ฟังก์ชั่น tmdatasetproxy.getVariant (aindex: จำนวนเต็ม): ตัวแปร; เริ่มต้นผลลัพธ์: = fdataset.fieldbyname (fproplist.propnames [aindex]) .value; ); ]). asfloat: = avalue; end; ขั้นตอน tmdatasetproxy.setstring (aindex: จำนวนเต็ม; avalue: string); startBeginedit; fdataset.fieldbyname (fproplist.propnames [aindex]). Aindex: Integer; เริ่มต้นขึ้น;
คลาส TMProplist คือการห่อหุ้มฟังก์ชั่นบางอย่างของการทำงานของแอตทริบิวต์ของ RTTI ฟังก์ชั่นของมันคือการใช้ฟังก์ชั่น RTTI บางอย่างที่กำหนดโดย Delphi ในหน่วย TypInfo เพื่อใช้คลาสที่ได้รับ TPersistent เพื่อรักษาข้อมูลรายการคุณสมบัติที่เผยแพร่ คลาสพร็อกซีได้รับชื่อแอตทริบิวต์ผ่านรายการแอตทริบิวต์นี้และในที่สุดก็ดำเนินการผ่านชื่อแอตทริบิวต์นี้และฟิลด์ที่เกี่ยวข้องในชุดข้อมูล
TMDATASETPROXY เป็นคลาสพื้นฐานของคลาสพร็อกซีชุดข้อมูล ส่วนที่สำคัญที่สุดคือการสร้างรายการคุณสมบัติในการก่อสร้างหลังการก่อสร้าง
การทำงานของแอตทริบิวต์ใช้เพียงสี่ประเภทข้อมูล: จำนวนเต็ม, double/float, สตริงและตัวแปร หากจำเป็นคุณสามารถรับคลาสฐานพร็อกซีของคุณเองบนพื้นฐานนี้เพื่อใช้การใช้งานประเภทข้อมูลอื่น ๆ การดำเนินการแทนที่มัน อย่างไรก็ตามสำหรับประเภทที่ไม่ได้ใช้กันมากขอแนะนำให้คุณกำหนดคลาสพร็อกซีจริงก่อนที่จะนำไปใช้ ตัวอย่างเช่นในตัวอย่างก่อนหน้าโดยสมมติว่า tdatetime ไม่ใช่ประเภทที่ใช้กันทั่วไปคุณสามารถทำได้:
TDSPEMPOLYEE = Class (TMDATASETPROXY) ฟังก์ชั่น GETDATETIME (ดัชนี const: จำนวนเต็ม): TDATETIME; GetString Write SetString; (getVariant (ดัชนี)); end; ขั้นตอน TDSPEMPLOYEE.SETDATETIME (ดัชนี const: จำนวนเต็ม; ค่า const: TDATETIME);
ด้วยวิธีนี้คุณสามารถใช้วันเกิดโดยตรงเป็นประเภท tdatetime
นอกจากนี้การใช้ประโยชน์จากสิ่งนี้เป็นไปได้ที่จะให้การดำเนินการแบบครบวงจรสำหรับประเภทข้อมูลพิเศษที่กำหนดเอง
นอกจากนี้การเริ่มต้นใช้งานก่อนที่ SETXXX ทั้งหมดจะหลีกเลี่ยงข้อผิดพลาดรันไทม์ที่เกิดจากการลืมใช้ DataSet.edit
Foreach ถูกนำมาใช้เพื่อนำมาใช้ใหม่ นอกจากนี้ Endedit จะถูกเรียกก่อนถัดไปเพื่อส่งการเปลี่ยนแปลงโดยอัตโนมัติ
รูปแบบการคัดค้านชุดข้อมูลนี้เป็นวิธีแก้ปัญหาที่ง่ายมาก นี่เป็นเพราะ Delphi ยังคงเป็นภาษาการพัฒนาดั้งเดิมหลังจากทั้งหมด ไม่มีไดนามิกดังนั้นคุณสามารถใช้วิธีการปัจจุบันในการลงทะเบียนเท่านั้น