Apakah SQL inline masih digolongkan sebagai praktik buruk sekarang karena kami memiliki Mikro ORM?

26

Ini sedikit pertanyaan terbuka tapi saya ingin beberapa pendapat, karena saya tumbuh di dunia di mana skrip SQL inline adalah norma, maka kita semua dibuat sangat sadar akan masalah berbasis injeksi SQL, dan seberapa rapuh sql ketika melakukan manipulasi string di semua tempat.

Kemudian tibalah awal dari ORM di mana Anda menjelaskan kueri ke ORM dan membiarkannya menghasilkan SQL sendiri, yang dalam banyak kasus tidak optimal tetapi aman dan mudah. Hal baik lainnya tentang ORM atau lapisan abstraksi basis data adalah bahwa SQL dihasilkan dengan mesin basis datanya, jadi saya bisa menggunakan Hibernate / Nhibernate dengan MSSQL, MYSQL dan kode saya tidak pernah berubah, itu hanya detail konfigurasi.

Sekarang maju cepat ke hari ini, di mana Mikro ORM tampaknya menang atas lebih banyak pengembang. Saya bertanya-tanya mengapa kami tampaknya mengambil U-Turn pada seluruh subjek sql in-line.

Saya harus mengakui bahwa saya menyukai gagasan tidak ada file konfigurasi ORM dan dapat menulis permintaan saya dengan cara yang lebih optimal tetapi rasanya seperti saya membuka diri kembali ke kerentanan lama seperti injeksi SQL dan saya juga mengikat diri untuk satu mesin basis data jadi jika saya ingin perangkat lunak saya mendukung beberapa mesin basis data saya perlu melakukan beberapa peretasan string yang tampaknya kemudian mulai membuat kode tidak dapat dibaca dan lebih rapuh. (Tepat sebelum seseorang menyebutkannya, saya tahu Anda dapat menggunakan argumen berbasis parameter dengan kebanyakan mikro orms yang menawarkan perlindungan dalam kebanyakan kasus dari injeksi sql)

Jadi apa pendapat orang tentang hal semacam ini? Saya menggunakan Dapper sebagai Mikro ORM saya dalam hal ini dan NHibernate sebagai ORM biasa saya dalam skenario ini, namun sebagian besar di setiap bidang sangat mirip.

Apa yang saya sebut sebagai inline sqladalah string SQL dalam kode sumber. Dulu ada perdebatan desain atas string SQL dalam kode sumber yang mengurangi niat mendasar dari logika, itulah sebabnya mengapa gaya query linq yang diketik secara statis menjadi sangat populer hingga hanya 1 bahasa, tetapi dengan katakanlah C # dan Sql dalam satu halaman yang Anda miliki 2 bahasa bercampur dalam kode sumber mentah Anda sekarang. Hanya untuk memperjelas, injeksi SQL hanyalah salah satu masalah yang diketahui dengan menggunakan string sql, saya sudah menyebutkan Anda dapat menghentikan hal ini terjadi dengan query berbasis parameter, namun saya menyoroti masalah lain dengan memiliki query SQL yang tertanam dalam kode sumber Anda, seperti kurangnya abstraksi DB Vendor serta kehilangan tingkat kesalahan waktu kompilasi pada permintaan berbasis string, semua ini adalah masalah yang kami berhasil selangkahi dengan fajar ORM dengan fungsionalitas kueri tingkat yang lebih tinggi,

Jadi saya kurang fokus pada isu-isu yang disoroti secara individu dan lebih banyak gambaran yang lebih besar dari sekarang menjadi lebih dapat diterima untuk memiliki string SQL langsung dalam kode sumber Anda lagi, karena kebanyakan Mikro ORM menggunakan mekanisme ini.

Berikut adalah pertanyaan serupa yang memiliki beberapa sudut pandang berbeda, meskipun lebih tentang sql inline tanpa konteks organisasi mikro:

/programming/5303746/is-inline-sql-hard-coding

Grofit
sumber
1
Apakah Anda pikir Anda bisa mengulangi pertanyaan sedemikian rupa sehingga tidak meminta pendapat? Polling untuk pendapat tidak cocok dengan format Tanya Jawab Stack Exchange.
Anda selalu dapat mengabstraksi kueri "Mikro ORM" Anda di kelas yang terpisah, di mana bila perlu Anda menukar kueri yang dieksekusi saat Anda mengubah DBMS Anda.
CodeCaster
belum pernah mendengar istilah "Mikro ORM". maksud Anda ORM yang tidak berusaha untuk sepenuhnya mengambil alih SQL, atau itu sesuatu yang berbeda?
Javier
tidak masalah, setelah sedikit googling, tampaknya menjadi hal bersih.
Javier
1
@GrandmasterB: Jelaskan mengapa dalam sebuah jawaban. Saya sudah cukup mengesampingkan masalah itu dalam jawaban saya, karena saya percaya itu adalah masalah pengorbanan.
Robert Harvey

Jawaban:

31

Apa yang Anda gambarkan sebagai "Inline SQL" harus benar-benar disebut "string concatenation tanpa parameterisasi," dan Anda tidak harus melakukan itu untuk menggunakan Micro ORM dengan aman.

Pertimbangkan contoh Dapper ini:

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

Ini sepenuhnya parameter, meskipun penggabungan string sedang berlangsung. Lihat tanda @?

Atau contoh ini:

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

yang kira-kira setara dengan kode ADO.NET berikut:

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 });
        }
    }
}

Jika Anda membutuhkan fleksibilitas lebih dari ini, Dapper menyediakan SQL Templates dan sebuah AddDynamicParms()fungsi. Semua SQL Injection aman.

Jadi mengapa menggunakan string SQL?

Nah, untuk alasan yang sama Anda akan menggunakan SQL kustom di ORM lain. Mungkin ORM adalah sub-optimal SQL penghasil kode, dan Anda perlu mengoptimalkannya. Mungkin Anda ingin melakukan sesuatu yang sulit dilakukan di ORM secara asli, seperti UNION. Atau, mungkin Anda hanya ingin menghindari kerumitan menghasilkan semua kelas proxy tersebut.

Jika Anda benar-benar tidak ingin menulis string SQL untuk setiap metode CRUD di Dapper (siapa yang melakukannya?), Anda dapat menggunakan perpustakaan ini:

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

Itu akan membuat Anda CRUD sangat sederhana dan mudah, sambil tetap memberi Anda fleksibilitas pernyataan SQL yang ditulis tangan. Ingat, contoh ADO.NET di atas adalah cara semua orang melakukannya sebelum ORM muncul; Dapper hanyalah lapisan tipis di atasnya.

Robert Harvey
sumber
Contoh yang baik, saya sudah menyebutkan bahwa Anda dapat menghindari injeksi SQL melalui parameter, karena ini hanya satu bagian dari pertanyaan yang lebih besar, juga menambahkan suntingan yang menjelaskan apa yang saya maksud ketika saya menggunakan istilah inline sql .
Grofit
Saya telah menambahkan beberapa detail pada jawaban saya.
Robert Harvey
2
+1 untuk informasi tentang SimpleCRUD tidak tahu ini ada.
Grofit
Di Jawa Anda akan menemukan Mybatis yang lebih ligther dari Hibernate atau EclipseLink dan. Caranya adalah dengan kalimat yang sudah ditentukan sebelumnya dalam XML (bukan hardcoding pada kode). Ini juga menambahkan beberapa fitur menarik sebagai prasyarat untuk meningkatkan SQL final. Kami menggunakan baru-baru ini ke web API yang memiliki konkurensi yang cukup tinggi dan bisnis yang tidak kompleks dan bekerja dengan baik.
Laiv
2

Saya suka sql , dan tidak tahan melihatnya dipotong dalam string literal, jadi saya menulis ekstensi VS kecil untuk memungkinkan Anda bekerja dengan file sql nyata dalam proyek-proyek c #. Mengedit sql dalam file-nya sendiri memberi Anda intellisense untuk kolom dan tabel, validasi sintaksis, eksekusi tes, rencana eksekusi, dan yang lainnya. Saat Anda menyimpan file, ekstensi saya menghasilkan kelas c # wrapper, jadi Anda tidak pernah menulis baris kode koneksi, atau kode perintah, atau parameter atau kode pembaca. Semua pertanyaan Anda diparameterisasi karena tidak ada cara lain, dan Anda telah membuat repositori dan POCO untuk pengujian unit, dengan intellisense untuk parameter input dan hasil Anda.

Dan saya telah melemparkan pisau steak gratis ... Ketika seorang ahli perlu datang dan mengerjakan ulang sql pengembang Anda, dia melihat file sql nyata, dan tidak perlu menyentuh C #. Ketika dia kembali dan merapikan DB, menghapus beberapa kolom, referensi ke kolom yang hilang langsung melompat sebagai kesalahan kompilasi dalam c #. Basis data menjadi seperti proyek lain dalam solusi Anda yang dapat Anda peretas, antarmuka ini dapat ditemukan dalam kode. Jika solusinya dikompilasi, Anda tahu bahwa semua kueri Anda berfungsi. Tidak ada kesalahan runtime karena gips tidak valid atau nama kolom tidak valid, atau kueri tidak valid.

Lihat kembali necis, yang masih kami gunakan di tempat kerja, saya tidak percaya bahwa pada tahun 2016 ini adalah hal paling keren dalam akses data. Generasi msil Runtime pandai n semua, tetapi semua kesalahan adalah kesalahan runtime, dan manipulasi string, seperti manipulasi string untuk tujuan lain, memakan waktu, rapuh dan rentan kesalahan. Dan bagaimana bisa Dry harus mengulangi nama kolom Anda di POCO Anda, yang harus Anda tulis dan pertahankan dengan tangan.

Jadi begitulah. Jika Anda ingin melihat teknologi akses data yang tidak dikenal dari pengembang yang tidak dikenal yang bekerja di waktu luangnya (dengan anak kecil dan banyak hobi lainnya), ada di sini .

bbsimonbb
sumber
Anda tampaknya berpikir banyak tentang "inovasi" kecil Anda, tetapi bagaimana ini berbeda dari, katakanlah, ExecuteStoreQuery atau ExecuteStoreCommand dalam Entity Framework?
Robert Harvey
Saya tidak masuk ke perdebatan EF atau SQL. Masalah saya adalah untuk orang-orang yang ingin menggunakan SQL. Jadi sebagai cara mengeksekusi SQL, ExecuteStoreQuery () akan mengisi POCO Anda untuk Anda, tetapi Anda masih perlu mendefinisikan POCO Anda, berdasarkan tampilan? Dan itu tidak membantu Anda menempatkan sql dalam file, atau membuat parameter Anda. Permintaan Anda tidak dapat ditemukan dalam kode, atau dapat diuji. Menghapus kolom tidak akan menghasilkan kesalahan kompilasi dalam aplikasi Anda. Saya bisa melanjutkan, tapi saya khawatir saya mengulangi sendiri :-) Mungkin Anda bisa mengambil 3mins untuk menonton video youtube. Itu dalam bahasa Prancis, matikan suaranya! Bahasa inggris datang
bbsimonbb
EF cukup mampu menghasilkan semua POCO secara otomatis. Apa yang kulewatkan di sini? Inovasi nyata dari Dapper dan Massive adalah Anda tidak memerlukan POCO sama sekali; Anda bisa menggunakannya dynamic.
Robert Harvey
Saya hampir tidak tahu apa-apa tentang EF. ExecuteStoreQuery () akan mengisi entitas. Akankah ia menghasilkan entitas dari kueri . Entitas dihasilkan dari objek DB (atau sebaliknya), bukan dari kueri. Jika kueri Anda tidak sesuai dengan entitas yang ada, Anda harus menulis POCO Anda, bukan?
bbsimonbb
1
:-) harus mengatakan saya mulai sensitif terhadap biaya iklan ketika saya meletakkan ide terbaik saya di luar sana. Inilah sedikit komersialisme agresif terbaru saya. Pada tanda 3 menit, Anda harus tahu apakah saya menyukai sesuatu atau tidak.
bbsimonbb
1

Kueri yang diparameterisasi serta pola desain repositori memberi Anda kendali penuh atas apa yang masuk ke dalam kueri untuk mencegah serangan injeksi. SQL inline dalam hal ini bukan masalah selain keterbacaan untuk pertanyaan besar dan kompleks, yang harus tetap tersimpan dalam prosedur.

Kyle JV
sumber