ใช่การเข้ารหัสสตริง SQL ลงในโค้ดของแอปพลิเคชั่นโดยทั่วไปเป็นรูปแบบการต่อต้าน
ลองแยกความอดทนที่เราได้พัฒนามานานหลายปีเพื่อดูสิ่งนี้ในรหัสการผลิต การผสมภาษาที่แตกต่างอย่างสมบูรณ์กับไวยากรณ์ที่แตกต่างกันในไฟล์เดียวกันโดยทั่วไปไม่ใช่เทคนิคการพัฒนาที่ต้องการ สิ่งนี้แตกต่างจากภาษาแม่แบบเช่นมีดโกนซึ่งออกแบบมาเพื่อให้ความหมายเชิงบริบทกับหลายภาษา ตามที่Sava B.ระบุไว้ในความคิดเห็นด้านล่าง SQL ในภาษา C # ของคุณหรือภาษาแอปพลิเคชันอื่น (Python, C ++ ฯลฯ ) เป็นสตริงที่เหมือนกันและไม่มีความหมาย เช่นเดียวกันเมื่อใช้มากกว่าหนึ่งภาษาในกรณีส่วนใหญ่แม้ว่าจะมีสถานการณ์ที่เห็นได้ชัดว่ายอมรับได้เช่น inline assembly ใน C ตัวอย่างเล็ก ๆ และเข้าใจได้ของ CSS ใน HTML (สังเกตว่า CSS ถูกออกแบบให้ผสมกับ HTML ), และคนอื่น ๆ.
(โรเบิร์ตซี. มาร์ตินเกี่ยวกับภาษาผสม, รหัสสะอาด , บทที่ 17, "รหัสกลิ่นและการวิเคราะห์ปัญหา", หน้า 288)
สำหรับการตอบสนองนี้ฉันจะเน้น SQL (ตามที่ถามในคำถาม) ปัญหาต่อไปนี้อาจเกิดขึ้นเมื่อเก็บ SQL เป็นชุดตามสั่งของสตริงที่ไม่เชื่อมโยงกัน:
- ตรรกะฐานข้อมูลยากต่อการค้นหา คุณค้นหาอะไรเพื่อค้นหาคำสั่ง SQL ทั้งหมดของคุณ? มากับ "SELECT", "UPDATE", "MERGE" ฯลฯ ไหม?
- การปรับโครงสร้างการใช้ SQL เดียวกันหรือคล้ายกันกลายเป็นเรื่องยาก
- การเพิ่มการรองรับฐานข้อมูลอื่นนั้นทำได้ยาก เราจะทำสิ่งนี้ให้สำเร็จได้อย่างไร? เพิ่มถ้า .. แล้วคำสั่งสำหรับแต่ละฐานข้อมูลและเก็บแบบสอบถามทั้งหมดเป็นสตริงในวิธีการหรือไม่
- นักพัฒนาอ่านคำแถลงในภาษาอื่นและหันเหความสนใจโดยการเปลี่ยนจุดสนใจจากจุดประสงค์ของวิธีการเป็นรายละเอียดการใช้งานของวิธีการ
- ในขณะที่หนึ่ง liners อาจไม่มากเกินไปปัญหาสตริง SQL แบบอินไลน์เริ่มที่จะกระจุยเป็นงบที่ซับซ้อนมากขึ้น คุณจะทำอย่างไรกับคำสั่งบรรทัด 113? ใส่ 113 บรรทัดทั้งหมดในวิธีการของคุณ?
- นักพัฒนาทำการย้ายแบบสอบถามไปมาระหว่างตัวแก้ไข SQL (SSMS, SQL Developer, etc. ) และซอร์สโค้ดอย่างมีประสิทธิภาพได้อย่างไร
@
คำนำหน้าของ C # ทำให้การดำเนินการนี้ง่ายขึ้น แต่ฉันได้เห็นโค้ดจำนวนมากที่อ้างอิงแต่ละบรรทัด SQL และหนีการขึ้นบรรทัดใหม่
"SELECT col1, col2...colN"\
"FROM painfulExample"\
"WHERE maintainability IS NULL"\
"AND modification.effort > @necessary"\
- อักขระการเยื้องที่ใช้เพื่อจัดแนว SQL กับโค้ดแอ็พพลิเคชันโดยรอบจะถูกส่งผ่านเครือข่ายด้วยการประมวลผลแต่ละครั้ง นี่อาจไม่สำคัญสำหรับแอปพลิเคชั่นขนาดเล็ก แต่สามารถเพิ่มได้เมื่อการใช้งานของซอฟต์แวร์เพิ่มขึ้น
ORM เต็มรูปแบบ (ตัวแม็พ Object-Relational เช่น Entity Framework หรือ Hibernate) สามารถกำจัด SQL ที่ใช้ peppered แบบสุ่มในโค้ดแอปพลิเคชัน การใช้งาน SQL และไฟล์ทรัพยากรของฉันเป็นเพียงตัวอย่าง ORMs คลาสผู้ช่วยและอื่น ๆ ทั้งหมดสามารถช่วยให้บรรลุเป้าหมายของโค้ดที่สะอาดขึ้น
ดังที่ Kevin กล่าวไว้ในคำตอบก่อนหน้านี้ SQL ในโค้ดสามารถยอมรับได้ในโครงการขนาดเล็ก แต่โครงการขนาดใหญ่เริ่มต้นจากโครงการขนาดเล็กและความน่าจะเป็นที่ทีมส่วนใหญ่จะกลับไปทำในสิ่งที่ถูกต้องมักจะแปรผกผัน
มีหลายวิธีที่ง่ายในการเก็บ SQL ไว้ในโครงการ หนึ่งในวิธีการที่ฉันมักใช้คือการใส่คำสั่ง SQL แต่ละคำลงในไฟล์ทรัพยากร Visual Studio โดยปกติจะมีชื่อว่า "sql" ไฟล์ข้อความเอกสาร JSON หรือแหล่งข้อมูลอื่นอาจมีเหตุผลขึ้นอยู่กับเครื่องมือของคุณ ในบางกรณีคลาสแยกต่างหากที่อุทิศให้กับการเชื่อมสตริง SQL อาจเป็นตัวเลือกที่ดีที่สุด แต่อาจมีบางประเด็นที่อธิบายไว้ข้างต้น
ตัวอย่าง SQL: รูปลักษณ์ใดที่สวยงามกว่า:
using(DbConnection connection = Database.SystemConnection()) {
var eyesoreSql = @"
SELECT
Viewable.ViewId,
Viewable.HelpText,
PageSize.Width,
PageSize.Height,
Layout.CSSClass,
PaginationType.GroupingText
FROM Viewable
LEFT JOIN PageSize
ON PageSize.Id = Viewable.PageSizeId
LEFT JOIN Layout
ON Layout.Id = Viewable.LayoutId
LEFT JOIN Theme
ON Theme.Id = Viewable.ThemeId
LEFT JOIN PaginationType
ON PaginationType.Id = Viewable.PaginationTypeId
LEFT JOIN PaginationMenu
ON PaginationMenu.Id = Viewable.PaginationMenuId
WHERE Viewable.Id = @Id
";
var results = connection.Query<int>(eyesoreSql, new { Id });
}
กลายเป็น
using(DbConnection connection = Database.SystemConnection()) {
var results = connection.Query<int>(sql.GetViewable, new { Id });
}
SQL มักจะอยู่ในไฟล์ที่ง่ายต่อการค้นหาหรือชุดของไฟล์ที่จัดกลุ่มแต่ละชื่อที่มีคำอธิบายที่อธิบายสิ่งที่มันทำมากกว่าวิธีที่มันทำแต่ละที่มีพื้นที่สำหรับความคิดเห็นที่จะไม่ขัดขวางการไหลของรหัสแอพลิเคชัน :
วิธีการง่ายๆนี้ดำเนินการค้นหาแบบแยกเดี่ยว จากประสบการณ์ของฉันผลประโยชน์จะเพิ่มขึ้นเมื่อใช้ "ภาษาต่างประเทศ" เพิ่มความซับซ้อนมากขึ้น
การใช้ไฟล์ทรัพยากรของฉันเป็นเพียงตัวอย่าง วิธีการที่แตกต่างกันอาจเหมาะสมกว่าขึ้นอยู่กับภาษา (SQL ในกรณีนี้) และแพลตฟอร์ม
วิธีนี้และวิธีอื่น ๆ แก้ไขรายการข้างต้นในลักษณะดังต่อไปนี้:
- รหัสฐานข้อมูลนั้นง่ายต่อการค้นหาเนื่องจากมีการรวมศูนย์ไว้แล้ว ในโครงการขนาดใหญ่กลุ่มเช่น-SQL
SQL
เป็นไฟล์แยกต่างหากบางทีภายใต้โฟลเดอร์ชื่อ
- รองรับฐานข้อมูลที่สอง, สามและอื่น ๆ ได้ง่ายขึ้น สร้างอินเทอร์เฟซ (หรือภาษาอื่น ๆ ที่เป็นนามธรรม) ที่ส่งคืนคำสั่งเฉพาะของฐานข้อมูลแต่ละตัว การใช้งานสำหรับแต่ละฐานข้อมูลจะน้อยกว่าคำสั่งที่คล้ายกับ:
return SqlResource.DoTheThing;
จริงการใช้งานเหล่านี้สามารถข้ามทรัพยากรและมี SQL ในสตริง แต่ปัญหาบางอย่าง (ไม่ใช่ทั้งหมด) ข้างต้นจะยังคงปรากฏ
- การปรับโครงสร้างใหม่นั้นง่าย - เพียงใช้ทรัพยากรเดียวกันซ้ำ คุณยังสามารถใช้รายการทรัพยากรเดียวกันสำหรับระบบ DBMS ที่แตกต่างกันได้บ่อยครั้งด้วยคำสั่งรูปแบบบางอย่าง ฉันทำสิ่งนี้บ่อยๆ
- การใช้ภาษาทุติยภูมิสามารถใช้ชื่อที่สื่อความหมายเช่น
sql.GetOrdersForAccount
แทนที่จะเป็นป้านมากกว่าSELECT ... FROM ... WHERE...
- คำสั่ง SQL ถูกเรียกด้วยหนึ่งบรรทัดโดยไม่คำนึงถึงขนาดและความซับซ้อน
- SQL สามารถคัดลอกและวางระหว่างเครื่องมือฐานข้อมูลเช่น SSMS และ SQL Developer โดยไม่ต้องดัดแปลงหรือคัดลอกอย่างระมัดระวัง ไม่มีเครื่องหมายคำพูด ไม่มีแบ็กสแลชต่อท้าย ในกรณีของตัวแก้ไขทรัพยากร Visual Studio โดยเฉพาะคลิกเดียวเน้นคำสั่ง SQL CTRL + C แล้ววางลงในตัวแก้ไข SQL
การสร้าง SQL ในทรัพยากรนั้นรวดเร็วดังนั้นจึงมีแรงกระตุ้นเล็กน้อยในการผสมการใช้ทรัพยากรกับ SQL-in-code
โดยไม่คำนึงถึงวิธีการที่เลือกฉันพบว่าภาษาผสมมักจะลดคุณภาพของรหัส ฉันหวังว่าปัญหาและแนวทางแก้ไขบางอย่างที่อธิบายไว้ที่นี่จะช่วยให้นักพัฒนากำจัดรหัสกลิ่นนี้เมื่อเหมาะสม