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.