SQL inline è ancora classificato come cattiva pratica ora che abbiamo Micro ORM?


26

Questa è una domanda un po 'aperta ma volevo alcune opinioni, poiché sono cresciuto in un mondo in cui gli script SQL in linea erano la norma, quindi eravamo tutti molto consapevoli dei problemi basati sull'iniezione SQL e di quanto fosse fragile la sql quando facendo manipolazioni di stringhe dappertutto.

Poi è arrivata l'alba dell'ORM in cui stavi spiegando la query all'ORM e facendogli generare il proprio SQL, che in molti casi non era ottimale ma era sicuro e facile. Un'altra cosa positiva degli ORM o dei livelli di astrazione del database è che l'SQL è stato generato pensando al suo motore di database, quindi ho potuto usare Hibernate / Nhibernate con MSSQL, MYSQL e il mio codice non è mai cambiato, era solo un dettaglio di configurazione.

Ora avanziamo rapidamente ai giorni nostri, dove i Micro ORM sembrano conquistare più sviluppatori e mi chiedevo perché apparentemente abbiamo fatto un'inversione di marcia sull'intero argomento sql in linea.

Devo ammettere che mi piace l'idea di nessun file di configurazione ORM e di essere in grado di scrivere la mia query in un modo più ottimale, ma mi sento come se stessi riaprendo le vecchie vulnerabilità come SQL injection e mi sto anche legando a un motore di database, quindi se voglio che il mio software supporti più motori di database, dovrei fare un po 'di hacking di stringhe che sembra quindi iniziare a rendere il codice illeggibile e più fragile. (Poco prima che qualcuno lo menzioni, so che è possibile utilizzare argomenti basati su parametri con la maggior parte dei microorganismi che offrono protezione nella maggior parte dei casi dall'iniezione sql)

Quindi quali sono le opinioni delle persone su questo genere di cose? Sto usando Dapper come Micro ORM in questo caso e NHibernate come ORM normale in questo scenario, tuttavia la maggior parte in ciascun campo sono abbastanza simili.

Quello che io chiamo inline sqlsono stringhe SQL nel codice sorgente. Ci sono stati dibattiti di progettazione sulle stringhe SQL nel codice sorgente che toglie l'intento fondamentale della logica, motivo per cui le query in stile linq tipicamente statiche sono diventate così popolari nella sua ancora solo 1 lingua, ma con diciamo C # e Sql in una pagina che hai 2 lingue mescolate nel tuo codice sorgente grezzo ora. Giusto per chiarire, l'iniezione SQL è solo uno dei problemi noti con l'utilizzo di stringhe sql, ho già detto che puoi impedire che ciò accada con query basate su parametri, tuttavia evidenzio altri problemi con le query SQL radicate nel codice sorgente, come la mancanza di astrazione di DB Vendor e la perdita di qualsiasi livello di errore di compilazione durante l'acquisizione di query basate su stringhe, sono tutti problemi che siamo riusciti a far fronte agli albori degli ORM con la loro funzionalità di query di livello superiore,

Quindi sono meno focalizzato sui singoli problemi evidenziati e più il quadro più ampio è ora che diventa più accettabile avere nuovamente stringhe SQL direttamente nel codice sorgente, poiché la maggior parte dei Micro ORM utilizza questo meccanismo.

Ecco una domanda simile che ha alcuni punti di vista diversi, anche se riguarda di più il sql inline senza il contesto micro orm:

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


1
Pensi di poter riformulare la domanda in modo tale da non chiedere un'opinione? Il polling per opinioni non si adatta bene al formato di domande e risposte di Stack Exchange.

Puoi sempre astrarre le tue query "Micro ORM" in una classe separata, dove quando necessario cambi le query che vengono eseguite mentre modifichi il tuo DBMS.
CodeCaster

non ho sentito il termine "Micro ORM". vuoi dire ORM che non tentano di prendere completamente su SQL, o è qualcosa di diverso?
Javier,

non importa, dopo aver cercato su Google un po ', sembra essere una cosa .net.
Javier,

1
@GrandmasterB: spiega perché in una risposta. Ho praticamente eluso questo problema nella mia risposta, poiché credo che sia una questione di compromessi.
Robert Harvey,

Risposte:


31

Quello che stai descrivendo come "Inline SQL" dovrebbe davvero essere chiamato "concatenazione di stringhe senza parametrizzazione" e non devi farlo per usare un Micro ORM in modo sicuro.

Considera questo esempio di Dapper:

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

È completamente parametrizzato, anche se si sta verificando una concatenazione di stringhe. Vedi il segno @?

O questo esempio:

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

che è approssimativamente equivalente al seguente codice 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 });
        }
    }
}

Se hai bisogno di maggiore flessibilità, Dapper fornisce modelli SQL e una AddDynamicParms()funzione. Tutte le SQL Injection sono sicure.

Quindi perché usare le stringhe SQL in primo luogo?

Bene, per gli stessi motivi useresti SQL personalizzato in qualsiasi altro ORM. Forse l'ORM sta generando codice SQL subottimale e devi ottimizzarlo. Forse vuoi fare qualcosa che è difficile fare nell'ORM in modo nativo, come le UNION. O forse vuoi semplicemente evitare la complessità di generare tutte quelle classi proxy.

Se davvero non vuoi scrivere una stringa SQL per ogni metodo CRUD in Dapper (chi lo fa?), Puoi usare questa libreria:

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

Ciò ti garantirà un CRUD estremamente semplice e diretto, offrendoti al contempo la flessibilità delle istruzioni SQL scritte a mano. Ricorda, l'esempio di ADO.NET sopra era il modo in cui lo facevano tutti prima che arrivasse l'ORM; Dapper è solo un'impiallacciatura sottile.


Buoni esempi, ho già menzionato che puoi eludere l'iniezione SQL tramite parametri, poiché questo è solo un pezzo della domanda più ampia, ho anche aggiunto una modifica che chiarisce cosa intendo quando uso il termine inline sql .
Grofit,

Ho aggiunto alcuni dettagli alla mia risposta.
Robert Harvey,

2
+1 per informazioni su SimpleCRUD non sapeva che esistesse.
Grofit,

In Java troverai Mybatis che è più grande di Hibernate o EclipseLink e. La sua strada da percorrere è attraverso frasi predefinite in XML (invece di hardcoding su codice). Aggiunge inoltre alcune funzionalità interessanti come precondizioni per migliorare l'SQL finale. Di recente abbiamo utilizzato un Web API con una concorrenza piuttosto elevata e un'attività non complessa e ha funzionato alla grande.
Laiv,

2

Adoro sql e non sopporto di vederlo suddiviso in letterali stringa, quindi ho scritto una piccola estensione VS per farti lavorare con file sql reali in progetti c #. La modifica di sql nel proprio file offre intellisense per colonne e tabelle, convalida della sintassi, esecuzione di test, piani di esecuzione e il resto. Quando salvi il file, la mia estensione genera classi wrapper c #, quindi non scrivi mai una riga di codice di connessione, codice di comando, parametro o codice del lettore. Le tue query sono tutte parametrizzate perché non c'è altro modo e hai generato repository e POCO per unit test, con intellisense per i parametri di input e i risultati.

E ho gettato coltelli da bistecca gratis ... Quando un esperto deve venire e rielaborare il sql del tuo sviluppatore, sta guardando un vero file sql e non ha bisogno di toccare C #. Quando torna indietro e riordina il DB, eliminando alcune colonne, i riferimenti alle colonne mancanti saltano fuori come errori di compilazione nel c #. Il database diventa proprio come un altro progetto nella tua soluzione in cui puoi hackerare, è un'interfaccia rilevabile nel codice. Se la soluzione viene compilata, sai che tutte le tue query funzionano. Non ci sono errori di runtime dovuti a cast non validi o nomi di colonne non validi o query non valide.

Guardando indietro a dapper, che stiamo ancora usando al lavoro, non posso credere che nel 2016 questa sia la cosa più bella nell'accesso ai dati. La generazione di msil di runtime è intelligente in tutti, ma tutti gli errori sono errori di runtime e la manipolazione delle stringhe, come la manipolazione delle stringhe per qualsiasi altro scopo, richiede tempo, è fragile e soggetta a errori. E come può essere secco dover ripetere i nomi delle colonne nel tuo POCO, che devi scrivere e conservare a mano.

Quindi eccoti. Se vuoi guardare una tecnologia di accesso ai dati sconosciuta da un inedito sviluppatore che lavora nel suo tempo libero (con un bambino piccolo e molti altri hobby), è finita qui .


Sembra che pensi molto alla tua piccola "innovazione", ma in che modo differisce, per esempio, da ExecuteStoreQuery o ExecuteStoreCommand in Entity Framework?
Robert Harvey,

Non sto entrando nel dibattito EF o SQL. La mia cosa è per le persone che vogliono usare SQL. Quindi, come modo di eseguire SQL, ExecuteStoreQuery () riempirà i tuoi POCO per te, ma devi ancora definire i tuoi POCO, dall'aspetto delle cose? E non fa nulla per aiutarti a mettere sql in un file o creare i tuoi parametri. La tua query non è rilevabile nel codice o non è verificabile. L'eliminazione delle colonne non produrrà errori di compilazione nella tua applicazione. Potrei continuare, ma temo di ripetermi :-) Forse potresti impiegare 3 minuti a guardare il video di YouTube. È in francese, abbassa il suono! Inglese in arrivo.
bbsimonbb,

EF è in grado di generare automaticamente tutti i POCO. Cosa mi sto perdendo qui? La vera innovazione di Dapper e Massive è che non hai assolutamente bisogno dei POCO; puoi semplicemente usare dynamic.
Robert Harvey,

Non so quasi nulla di EF. ExecuteStoreQuery () riempirà un'entità. Genererà un'entità dalla query . Le entità sono generate da oggetti DB (o viceversa), non da query. Se la tua query non corrisponde a un'entità esistente, devi scrivere il tuo POCO, no?
bbsimonbb,

1
:-) Devo dire che sto diventando sensibile alle accuse di pubblicità quando sto pubblicando la mia migliore idea liberamente. Ecco il mio ultimo pezzo di commercialismo aggressivo. Entro il segno dei 3 minuti, dovresti sapere se sono su qualcosa o no.
bbsimonbb,

1

Le query con parametri e il modello di progettazione del repository offrono il pieno controllo su ciò che va nella query per prevenire attacchi di iniezione. Inline SQL in questo caso non è altro che la leggibilità per query grandi e complesse, che dovrebbero comunque trovarsi nelle procedure memorizzate.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.