¿El SQL en línea todavía se clasifica como una mala práctica ahora que tenemos Micro ORM?

26

Esta es una pregunta un poco abierta, pero quería algunas opiniones, ya que crecí en un mundo donde los scripts SQL en línea eran la norma, entonces todos nos hicimos muy conscientes de los problemas basados ​​en la inyección SQL y cuán frágil era el sql cuando haciendo manipulaciones de cuerdas por todo el lugar.

Luego llegó el amanecer del ORM donde explicaba la consulta al ORM y le permitía generar su propio SQL, que en muchos casos no era óptimo pero era seguro y fácil. Otra cosa buena acerca de los ORM o las capas de abstracción de la base de datos fue que el SQL se generó teniendo en cuenta su motor de base de datos, por lo que pude usar Hibernate / Nhibernate con MSSQL, MYSQL y mi código nunca cambió, fue solo un detalle de configuración.

Ahora avanzando rápidamente hasta el día actual, donde Micro ORM parece estar ganando a más desarrolladores. Me preguntaba por qué aparentemente hemos dado un giro en U en todo el tema sql en línea.

Debo admitir que me gusta la idea de que no haya archivos de configuración ORM y poder escribir mi consulta de una manera más óptima, pero parece que me estoy abriendo nuevamente a las viejas vulnerabilidades como la inyección de SQL y también me estoy atando a un motor de base de datos, por lo que si quiero que mi software sea compatible con múltiples motores de base de datos, necesitaría hacer un poco más de piratería de cadenas que parece comenzar a hacer que el código sea ilegible y más frágil. (Justo antes de que alguien lo mencione, sé que puede usar argumentos basados ​​en parámetros con la mayoría de los micro orms que ofrecen protección en la mayoría de los casos contra la inyección sql)

Entonces, ¿cuáles son las opiniones de la gente sobre este tipo de cosas? Estoy usando Dapper como mi Micro ORM en este caso y NHibernate como mi ORM normal en este escenario, sin embargo, la mayoría en cada campo son bastante similares.

Lo que llamo sql en líneason cadenas SQL dentro del código fuente. Solía ​​haber debates de diseño sobre las cadenas SQL en el código fuente que restan valor a la intención fundamental de la lógica, razón por la cual las consultas de estilo linq escritas estáticamente se hicieron tan populares que todavía es solo 1 lenguaje, pero digamos C # y Sql en una página que tiene 2 idiomas entremezclados en su código fuente sin procesar ahora. Solo para aclarar, la inyección SQL es solo uno de los problemas conocidos con el uso de cadenas sql, ya menciono que puede evitar que esto suceda con consultas basadas en parámetros, sin embargo, destaco otros problemas con tener consultas SQL integradas en su código fuente, como la falta de abstracción de DB Vendor, así como la pérdida de cualquier nivel de captura de errores en el tiempo de compilación en consultas basadas en cadenas, todos estos son problemas que hemos logrado evitar con el inicio de los ORM con su funcionalidad de consulta de nivel superior,

Por lo tanto, estoy menos enfocado en los problemas individuales resaltados y más la idea general es que ahora es más aceptable tener cadenas SQL directamente en su código fuente nuevamente, ya que la mayoría de los Micro ORM usan este mecanismo.

Aquí hay una pregunta similar que tiene algunos puntos de vista diferentes, aunque trata más sobre el sql en línea sin el contexto de micro orm:

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

Grofit
fuente
1
¿Crees que podrías reformular la pregunta de tal manera que no pida una opinión? Las encuestas de opinión no encajan bien en el formato de preguntas y respuestas de Stack Exchange.
Siempre puede abstraer sus consultas "Micro ORM" en una clase separada, donde, cuando sea necesario, intercambie las consultas que se ejecutan a medida que cambia su DBMS.
CodeCaster
no he escuchado el término "Micro ORM". ¿te refieres a ORM que no intentan hacerse cargo de SQL por completo, o es algo diferente?
Javier
no importa, después de buscar un poco en Google, parece ser una cosa .net.
Javier
1
@GrandmasterB: Explique por qué en una respuesta. Casi he eludido ese problema en mi respuesta, ya que creo que es una cuestión de compensaciones.
Robert Harvey

Respuestas:

31

Lo que está describiendo como "SQL en línea" realmente debería llamarse "concatenación de cadenas sin parametrización", y no tiene que hacer eso para usar un Micro ORM de forma segura.

Considere este ejemplo Dapper:

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

Está completamente parametrizado, a pesar de que se está produciendo la concatenación de cadenas. ¿Ves el signo @?

O este ejemplo:

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

que es más o menos equivalente al siguiente código 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 });
        }
    }
}

Si necesita más flexibilidad que esto, Dapper proporciona plantillas SQL y una AddDynamicParms()función. Todas las inyecciones SQL son seguras.

Entonces, ¿por qué usar cadenas SQL en primer lugar?

Bueno, por las mismas razones que usarías SQL personalizado en cualquier otro ORM. Tal vez el ORM es un SQL subóptimo que genera código, y necesita optimizarlo. Tal vez desee hacer algo que es difícil de hacer en el ORM de forma nativa, como UNION. O, tal vez, simplemente desee evitar la complejidad de generar todas esas clases proxy.

Si realmente no desea escribir una cadena SQL para cada método CRUD en Dapper (¿quién lo hace?), Puede usar esta biblioteca:

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

Eso le proporcionará un CRUD extremadamente simple y directo, al tiempo que le brinda la flexibilidad de las declaraciones SQL escritas a mano. Recuerde, el ejemplo ADO.NET anterior fue la forma en que todos lo hicieron antes de que aparecieran los ORM; Dapper es solo una delgada capa sobre eso.

Robert Harvey
fuente
Buenos ejemplos, ya mencioné que puede eludir la inyección de SQL a través de parámetros, ya que esta es solo una parte de la pregunta más grande, también he agregado una edición que aclara lo que quiero decir cuando uso el término inline sql .
Grofit
He agregado algunos detalles a mi respuesta.
Robert Harvey
2
+1 para obtener información sobre SimpleCRUD no sabía que esto existía.
Grofit
En Java encontrará Mybatis, que está más allá de Hibernate o EclipseLink y. Su camino a seguir es mediante oraciones predefinidas en XML (en lugar de codificar en código). También agrega algunas características interesantes como condiciones previas para mejorar el SQL final. Recientemente utilizamos una API API que tiene una concurrencia bastante alta y un negocio no complejo y funcionó muy bien.
Laiv
2

Me encanta sql , y no podía soportar verlo cortado en literales de cadena, así que escribí una pequeña extensión VS para permitirle trabajar con archivos sql reales en proyectos de C #. La edición de sql en su propio archivo le proporciona inteligencia para columnas y tablas, validación de sintaxis, ejecución de pruebas, planes de ejecución y el resto. Cuando guardas el archivo, mi extensión genera clases de envoltura de C #, por lo que nunca escribes una línea de código de conexión, código de comando, parámetro o código de lector. Todas sus consultas están parametrizadas porque no hay otra manera, y ha generado repositorios y POCO para pruebas unitarias, con inteligencia para sus parámetros de entrada y sus resultados.

Y he tirado cuchillos de carne gratis ... Cuando un experto necesita venir y reelaborar el sql de su desarrollador, está mirando un archivo sql real, y no necesita tocar ningún C #. Cuando regresa y ordena la base de datos, eliminando algunas columnas, las referencias a las columnas que faltan saltan directamente como errores de compilación en el c #. La base de datos se convierte en otro proyecto en su solución que puede piratear, su interfaz se puede descubrir en código. Si la solución se compila, sabrá que todas sus consultas están funcionando. No hay errores de tiempo de ejecución debido a conversiones o nombres de columna no válidos, o consultas no válidas.

Mirando hacia atrás a Dapper, que todavía estamos usando en el trabajo, no puedo creer que en 2016 esto sea lo mejor en acceso a datos. La generación de msil en tiempo de ejecución es inteligente, pero todos los errores son errores de tiempo de ejecución, y la manipulación de cadenas, como la manipulación de cadenas para cualquier otro propósito, consume mucho tiempo, es frágil y propensa a errores. ¿Y cómo puede ser seco tener que repetir los nombres de las columnas en su POCO, que debe escribir y mantener a mano?

Ahí vas. Si desea ver una tecnología desconocida de acceso a datos de un desarrollador inaudito que trabaja en su tiempo libre (con un niño pequeño y muchos otros pasatiempos), está aquí .

bbsimonbb
fuente
Parece pensar mucho en su pequeña "innovación", pero ¿en qué se diferencia esto de, por ejemplo, ExecuteStoreQuery o ExecuteStoreCommand en Entity Framework?
Robert Harvey
No me estoy metiendo en el debate EF o SQL. Lo mío es para las personas que quieren usar SQL. Entonces, como una forma de ejecutar SQL, ExecuteStoreQuery () llenará sus POCO por usted, pero aún necesita definir sus POCO, por el aspecto de las cosas. Y no hace nada para ayudarlo a poner el sql en un archivo o crear sus parámetros. Su consulta no es reconocible en el código, ni comprobable. Eliminar columnas no producirá errores de compilación en su aplicación. Podría continuar, pero me temo que me estoy repitiendo :-) Quizás podrías tomar 3 minutos para ver el video de YouTube. Está en francés, baja el sonido! Inglés que viene.
bbsimonbb
EF es bastante capaz de generar todos los POCO automáticamente. ¿Que me estoy perdiendo aqui? La verdadera innovación de Dapper y Massive es que no necesita POCO en absoluto; solo puedes usar dynamic.
Robert Harvey
No sé casi nada sobre EF. ExecuteStoreQuery () llenará una entidad. ¿Generará una entidad a partir de la consulta ? Las entidades se generan a partir de objetos de base de datos (o viceversa), no a partir de consultas. Si su consulta no corresponde a una entidad existente, debe escribir su POCO, ¿no?
bbsimonbb
1
:-) debo decir que me estoy volviendo sensible a los cargos de publicidad cuando expongo mi mejor idea libremente. Aquí está mi último poco de comercialismo agresivo. Para la marca de 3 minutos, debe saber si estoy en algo o no.
bbsimonbb
1

Las consultas parametrizadas, así como el patrón de diseño del repositorio, le dan control total sobre lo que se incluye en la consulta para evitar ataques de inyección. El SQL en línea en este caso no es un problema que no sea la legibilidad para consultas grandes y complejas, que de todos modos deberían estar en procedimientos almacenados.

Kyle JV
fuente