SQL แบบอินไลน์ยังจัดอยู่ในประเภทการปฏิบัติที่ไม่ดีในขณะนี้ที่เรามี Micro ORMs หรือไม่?


26

นี่เป็นคำถามปลายเปิดเล็กน้อย แต่ฉันต้องการความคิดเห็นบางอย่างเนื่องจากฉันโตขึ้นในโลกที่สคริปต์ SQL แบบอินไลน์เป็นบรรทัดฐานจากนั้นเราทุกคนต่างก็ตระหนักถึงปัญหาการฉีด SQL ที่ใช้กันมากและ sql นั้นบอบบางเพียงใด ทำการปรับแต่งสตริงทั่วทุกที่

จากนั้นก็เริ่มรุ่งอรุณของ ORM ซึ่งคุณได้อธิบายการสืบค้นไปยัง ORM และปล่อยให้มันสร้าง SQL ของตัวเองซึ่งในหลายกรณีนั้นไม่เหมาะสมแต่ปลอดภัยและง่าย สิ่งที่ดีอีกอย่างเกี่ยวกับ ORMs หรือเลเยอร์สิ่งที่เป็นนามธรรมของเลเยอร์คือว่า SQL นั้นถูกสร้างขึ้นด้วยเอ็นจิ้นฐานข้อมูลของมันดังนั้นฉันสามารถใช้ Hibernate / Nhibernate กับ MSSQL, MYSQL และรหัสของฉันไม่เคยเปลี่ยน

ตอนนี้ก้าวไปข้างหน้าอย่างรวดเร็วจนถึงปัจจุบันซึ่ง Micro ORM ดูเหมือนจะชนะมากกว่านักพัฒนาอื่น ๆ ฉันสงสัยว่าทำไมเราถึงได้นำ U-Turn มาใช้กับเรื่องทั้งหมดในตาราง

ฉันต้องยอมรับว่าฉันชอบความคิดที่ว่าไม่มีไฟล์ ORM config และความสามารถในการเขียนข้อความค้นหาของฉันในลักษณะที่เหมาะสมที่สุด แต่รู้สึกเหมือนฉันกำลังเปิดตัวเองกลับสู่ช่องโหว่เก่า ๆ เช่นการฉีด SQL และฉันก็ผูกตัวเอง เอ็นจิ้นฐานข้อมูลหนึ่งดังนั้นถ้าฉันต้องการซอฟต์แวร์ของฉันเพื่อสนับสนุนเอนจินฐานข้อมูลหลายตัวฉันจะต้องทำการแฮ็คสตริงเพิ่มเติมซึ่งดูเหมือนว่าจะเริ่มทำให้โค้ดอ่านไม่ได้และเปราะบางยิ่งขึ้น (ก่อนที่ใครบางคนจะกล่าวถึงมันฉันรู้ว่าคุณสามารถใช้อาร์กิวเมนต์ที่อิงพารามิเตอร์กับ micro orms ส่วนใหญ่ที่ให้ความคุ้มครองในกรณีส่วนใหญ่จากการฉีด sql)

ดังนั้นความคิดเห็นของประชาชนในเรื่องนี้คืออะไร? ฉันใช้ Dapper เป็น Micro ORM ของฉันในอินสแตนซ์นี้และ NHibernate เป็น ORM ปกติของฉันในสถานการณ์นี้อย่างไรก็ตามส่วนใหญ่ในแต่ละฟิลด์นั้นค่อนข้างคล้ายกัน

สิ่งที่ฉันเรียกว่าอินไลน์ sqlคือสตริง SQL ภายในซอร์สโค้ด เคยมีการออกแบบการถกเถียงเกี่ยวกับสตริง SQL ในซอร์สโค้ดซึ่งแยกออกจากเจตนาพื้นฐานของตรรกะซึ่งเป็นสาเหตุที่แบบสอบถามสไตล์ linq ที่พิมพ์แบบคงที่กลายเป็นที่นิยมมากจนยังคงเป็นเพียงแค่ 1 ภาษา แต่ด้วยการบอกว่า C # และ Sql ในหน้าเดียว 2 ภาษาผสมกันในซอร์สโค้ดดิบของคุณทันที เพื่อชี้แจงการฉีด SQL เป็นเพียงหนึ่งในปัญหาที่รู้จักกับการใช้สตริง sql ฉันพูดถึงคุณสามารถหยุดสิ่งนี้เกิดขึ้นกับแบบสอบถามตามพารามิเตอร์ แต่ฉันเน้นปัญหาอื่น ๆ ด้วยการมีแบบสอบถาม SQL ฝังอยู่ในซอร์สโค้ดของคุณเช่น การขาด DB Vendor abstraction รวมถึงการสูญเสียข้อผิดพลาดในการรวบรวมเวลาในระดับใด ๆ ที่จับกับการสืบค้นแบบใช้สตริงซึ่งเป็นปัญหาทั้งหมดที่เราจัดการไปด้านข้างด้วยรุ่งอรุณของ ORMs ด้วยฟังก์ชันการสืบค้นระดับสูง

ดังนั้นฉันจึงให้ความสำคัญกับปัญหาที่เน้นเป็นรายบุคคลน้อยลงและภาพรวมที่ใหญ่ขึ้นคือตอนนี้กลายเป็นที่ยอมรับได้มากกว่าที่จะมีสตริง SQL ในซอร์สโค้ดของคุณโดยตรงอีกครั้งเนื่องจาก Micro ORM ส่วนใหญ่ใช้กลไกนี้

นี่คือคำถามที่คล้ายกันซึ่งมีมุมมองที่แตกต่างกันเล็กน้อยถึงแม้ว่าจะเป็นข้อมูลเพิ่มเติมเกี่ยวกับ sql แบบอินไลน์โดยไม่มีบริบท orm ขนาดเล็ก:

https://stackoverflow.com/questions/5303746/is-inline-sql-hard-coding


1
คุณคิดว่าคุณสามารถเรียบเรียงคำถามใหม่ในลักษณะที่ไม่ขอความเห็นได้หรือไม่? การสำรวจความคิดเห็นนั้นไม่เหมาะสมกับรูปแบบคำถามและคำตอบของ Stack Exchange

คุณสามารถสรุปแบบสอบถาม "Micro ORM" ของคุณในชั้นเรียนแยกต่างหากเมื่อใดที่คุณจำเป็นต้องสลับแบบสอบถามที่กำลังดำเนินการเมื่อคุณเปลี่ยน DBMS ของคุณ
CodeCaster

ไม่ได้ยินคำว่า "Micro ORM" คุณหมายถึง ORM ที่ไม่พยายามใช้ SQL อย่างสมบูรณ์หรือเป็นสิ่งที่แตกต่างออกไปหรือไม่?
Javier

ไม่เป็นไรหลังจาก googling เล็กน้อยดูเหมือนว่าจะเป็น. net
Javier

1
@GrandmasterB: อธิบายว่าทำไมในคำตอบ ฉันตอบคำถามของฉันไปทางด้านข้างเนื่องจากฉันเชื่อว่ามันเป็นคำถามของการแลกเปลี่ยน
Robert Harvey

คำตอบ:


31

สิ่งที่คุณอธิบายว่า "Inline SQL" ควรเรียกว่า "string concatenation โดยไม่ต้องใช้พารามิเตอร์" และคุณไม่จำเป็นต้องทำเช่นนั้นเพื่อใช้ Micro ORM อย่างปลอดภัย

ลองพิจารณาตัวอย่าง Dapper นี้:

string sql = "SELECT * from user_profile WHERE FirstName LIKE @name;";
var result = connection.Query<Profile>(sql, new {name = "%"+name+"%"});

มันเป็นพารามิเตอร์อย่างเต็มที่แม้ว่าการเรียงสตริงจะเกิดขึ้น เห็นสัญลักษณ์ @ หรือไม่

หรือตัวอย่างนี้:

var dog = connection.Query<Dog>("select Age = @Age, Id = @Id", 
          new { Age = (int?)null, Id = guid });

ซึ่งเทียบเท่ากับรหัส ADO.NET ต่อไปนี้:

List<Dog> dog = new List<Dog>();
using(var cmd = connection.CreateCommand()) {
    cmd.CommandText = "select Age = @Age, Id = @Id";
    cmd.Parameters.AddWithValue("Age", DBNull.Value);
    cmd.Parameters.AddWithValue("Id", guid);
    using(var reader = cmd.ExecuteReader()) {
        while(reader.Read()) {
            int age = reader.ReadInt32("Age");
            int id = reader.ReadInt32("Id");
            dog.Add(new Dog { Age = age, Id = id });
        }
    }
}

หากคุณต้องการความยืดหยุ่นมากกว่านี้ Dapper จะให้เทมเพลต SQL และAddDynamicParms()ฟังก์ชัน SQL Injection ทั้งหมดปลอดภัย

เหตุใดจึงต้องใช้สตริง SQL ตั้งแต่แรก?

ด้วยเหตุผลเดียวกันคุณจะใช้ SQL ที่กำหนดเองใน ORM อื่น ๆ บางที ORM เป็น SQL ที่สร้างโค้ดย่อยที่ดีที่สุดและคุณต้องปรับให้เหมาะสม บางทีคุณอาจต้องการทำบางสิ่งที่ยากต่อการทำใน ORM เช่นใน UNIONs หรือบางทีคุณอาจต้องการหลีกเลี่ยงความซับซ้อนในการสร้างคลาสพร็อกซีเหล่านั้นทั้งหมด

หากคุณไม่ต้องการเขียนสตริง SQL สำหรับทุกวิธีCRUDใน Dapper (ใครทำ) คุณสามารถใช้ไลบรารีนี้:

https://github.com/ericdc1/Dapper.SimpleCRUD/

ที่จะทำให้คุณได้รับ CRUD ที่ง่ายและตรงไปตรงมามากที่สุดในขณะที่ยังคงให้ความยืดหยุ่นของคำสั่ง SQL ที่เขียนด้วยมือ จำไว้ว่าตัวอย่าง ADO.NET ด้านบนเป็นวิธีที่ทุกคนทำก่อนที่ ORM จะเข้ามา Dapper เป็นเพียงแผ่นไม้อัดบาง ๆ


ตัวอย่างที่ดีที่ผมไม่อยู่แล้วพูดถึงว่าคุณสามารถหลีกเลี่ยงฉีด SQL ผ่านพารามิเตอร์เช่นนี้เป็นเพียงชิ้นส่วนหนึ่งในคำถามที่มีขนาดใหญ่นอกจากนี้ยังได้เพิ่มการแก้ไขชัดเจนสิ่งที่ฉันหมายถึงเมื่อฉันใช้ระยะSQL แบบอินไลน์
Grofit

ฉันได้เพิ่มรายละเอียดลงในคำตอบของฉันแล้ว
Robert Harvey

2
+1 สำหรับข้อมูลเกี่ยวกับ SimpleCRUD ไม่ทราบว่ามีอยู่จริง
Grofit

ใน Java คุณจะพบMybatisซึ่งเป็น ligther กว่า Hibernate หรือ EclipseLink และ วิธีที่จะไปคือโดยประโยคที่กำหนดไว้ล่วงหน้าใน XML (แทนที่จะเป็นรหัส hardcoding) นอกจากนี้ยังเพิ่มคุณสมบัติที่น่าสนใจบางอย่างเป็นเงื่อนไขเบื้องต้นเพื่อปรับปรุง SQL ขั้นสุดท้าย เมื่อเร็ว ๆ นี้เราใช้เป็นเว็บ API ที่มีการทำงานพร้อมกันค่อนข้างสูงและเป็นธุรกิจที่ไม่ซับซ้อนและใช้งานได้ดีมาก
Laiv

2

ฉันรัก sqlและทนไม่ได้ที่เห็นมันถูกสับเป็นตัวอักษรสตริงดังนั้นฉันจึงเขียนส่วนขยาย VS เล็กน้อยเพื่อให้คุณทำงานกับไฟล์ sql จริงในโครงการ c # การแก้ไข sql ในไฟล์ของตัวเองจะช่วยให้คุณใช้งาน Intellisense สำหรับคอลัมน์และตาราง, การตรวจสอบความถูกต้องของไวยากรณ์, การดำเนินการทดสอบ, แผนการดำเนินการและส่วนที่เหลือ เมื่อคุณบันทึกไฟล์ส่วนขยายของฉันจะสร้างคลาส c # wrapper ดังนั้นคุณจึงไม่ต้องเขียนบรรทัดของรหัสการเชื่อมต่อหรือรหัสคำสั่งหรือพารามิเตอร์หรือรหัสเครื่องอ่าน การสืบค้นของคุณทั้งหมดได้รับการทำให้เป็นพารามิเตอร์เนื่องจากไม่มีวิธีอื่นและคุณได้สร้างที่เก็บและ POCO สำหรับการทดสอบหน่วยโดยมีค่าอินทิลิสซิเดนซ์สำหรับพารามิเตอร์อินพุตและผลลัพธ์ของคุณ

และฉันถูกโยนด้วยมีดเสต็กฟรี ... เมื่อผู้เชี่ยวชาญต้องการมาทำใหม่และพัฒนา sql ของนักพัฒนาของคุณเธอกำลังดูไฟล์ sql จริงและไม่จำเป็นต้องแตะ C # ใด ๆ เมื่อเธอกลับไปและจัดระเบียบฐานข้อมูลการลบบางคอลัมน์การอ้างอิงไปยังคอลัมน์ที่หายไปจะกระโดดออกมาตรงๆเป็นข้อผิดพลาดในการคอมไพล์ใน c # ฐานข้อมูลจะเหมือนกับโครงการอื่น ๆ ในโซลูชันของคุณที่คุณสามารถแฮ็คเข้ามาได้ หากวิธีการแก้ปัญหารวบรวมคุณรู้ว่าแบบสอบถามทั้งหมดของคุณทำงาน ไม่มีข้อผิดพลาดรันไทม์เนื่องจาก casts ไม่ถูกต้องหรือชื่อคอลัมน์ไม่ถูกต้องหรือแบบสอบถามที่ไม่ถูกต้อง

มองย้อนกลับไปที่ dapper ซึ่งเรายังคงใช้ในที่ทำงานอยู่ฉันไม่อยากจะเชื่อเลยว่าในปี 2559 นี่เป็นสิ่งที่ยอดเยี่ยมที่สุดในการเข้าถึงข้อมูล การสร้าง msil แบบรันไทม์นั้นฉลาด แต่ทั้งหมดข้อผิดพลาดทั้งหมดเป็นข้อผิดพลาดแบบรันไทม์และการจัดการสตริงเช่นการจัดการสตริงเพื่อวัตถุประสงค์อื่น ๆ ใช้เวลานานเปราะบางและเกิดข้อผิดพลาดได้ง่าย และมันจะแห้งแค่ไหนที่จะต้องทำซ้ำชื่อคอลัมน์ใน POCO ของคุณซึ่งคุณต้องเขียนและดูแลด้วยมือ

ดังนั้นคุณไป หากคุณต้องการที่จะดูที่ไม่รู้จักเทคโนโลยีการเข้าถึงข้อมูลจากไม่เคยได้ยินจากนักพัฒนาทำงานในเวลาว่างของเขา (กับเด็กหนุ่มและจำนวนมากของงานอดิเรกอื่น ๆ ) มันมากกว่าที่นี่


คุณดูเหมือนจะคิดว่า "นวัตกรรม" ตัวเล็ก ๆ ของคุณมากมาย แต่สิ่งนี้แตกต่างจากExecuteStoreQueryหรือExecuteStoreCommandใน Entity Framework อย่างไร
Robert Harvey

ฉันไม่ได้เข้าร่วมการอภิปรายของ EF หรือ SQL สิ่งที่ฉันสำหรับชาวบ้านที่ต้องการใช้ SQL ดังนั้นวิธีดำเนินการ SQL, ExecuteStoreQuery () จะเติม POCO ของคุณให้คุณ แต่คุณยังต้องกำหนด POCO ของคุณโดยดูจากสิ่งต่าง ๆ หรือไม่? และมันก็ไม่มีอะไรช่วยให้คุณใส่ sql ในไฟล์หรือสร้างพารามิเตอร์ของคุณ แบบสอบถามของคุณไม่สามารถค้นพบได้ในรหัสหรือทดสอบได้ การลบคอลัมน์จะไม่ทำให้เกิดข้อผิดพลาดในการคอมไพล์ในแอปพลิเคชันของคุณ ฉันสามารถไปต่อได้ แต่ฉันกลัวว่าฉันจะทำซ้ำตัวเอง :-) บางทีคุณอาจใช้เวลา 3 นาทีในการดูวิดีโอ youtube มันเป็นภาษาฝรั่งเศสปิดเสียงลง! ภาษาอังกฤษกำลังมา
bbsimonbb

EF ค่อนข้างสามารถสร้าง POCO ทั้งหมดได้โดยอัตโนมัติ สิ่งที่ฉันหายไปที่นี่? นวัตกรรมที่แท้จริงของ Dapper และ Massive คือคุณไม่จำเป็นต้องใช้ POCO เลย dynamicคุณก็สามารถใช้
Robert Harvey

ฉันไม่รู้อะไรเกี่ยวกับ EF ExecuteStoreQuery () จะเติมเอนทิตี มันจะสร้างเอนทิตีจากแบบสอบถามหรือไม่ เอนทิตีถูกสร้างขึ้นจากวัตถุ DB (หรือในทางกลับกัน) ไม่ใช่จากการสืบค้น หากคำค้นหาของคุณไม่ตรงกับองค์กรที่มีอยู่คุณต้องเขียน POCO ของคุณใช่ไหม
bbsimonbb

1
:-) ต้องบอกว่าฉันมีความรู้สึกไวต่อค่าใช้จ่ายการโฆษณาเมื่อฉันวางความคิดที่ดีที่สุดของฉันไว้ที่นั่นอย่างอิสระ นี่คือบิตเชิงพาณิชย์เชิงรุกล่าสุดของฉัน เมื่อถึงเครื่องหมาย 3 นาทีคุณควรรู้ว่าฉันทำอะไรลงไปบ้างหรือเปล่า
bbsimonbb

1

Parameterized query รวมถึงรูปแบบการออกแบบพื้นที่เก็บข้อมูลให้คุณควบคุมสิ่งที่จะเข้าไปในแบบสอบถามเพื่อป้องกันการโจมตีของการฉีด Inline SQL ในกรณีนี้ไม่ใช่ปัญหาอื่นนอกจากความสามารถในการอ่านสำหรับคิวรีขนาดใหญ่และซับซ้อนซึ่งควรอยู่ในขั้นตอนการจัดเก็บอยู่ดี

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.