¿Mejor práctica para consultar datos de MS SQL Server en C #?

9

¿Cuál es la mejor manera de consultar datos de un servidor MS SQL en C #?

Sé que no es una buena práctica tener una consulta SQL en el código.

¿Es la mejor manera de crear un procedimiento almacenado y llamarlo desde C # con parámetros?

using (var conn = new SqlConnection(connStr))
using (var command = new SqlCommand("StoredProc", conn) { CommandType = CommandType.StoredProcedure }) {
   conn.Open();
   command.ExecuteNonQuery();
   conn.Close();
}
Bruno
fuente
8
"Sé que no es una buena práctica tener una consulta SQL en el código". - Oye, eso no tiene sentido.
GrandmasterB
44
No tiene que llamar a conn.Close () si lo creó en un bloque de uso. El objetivo del bloque de uso es imitar el estilo C ++ de limpieza del destructor. Una limpieza elegante de una época más civilizada. No es tan aleatorio o torpe como el estilo try-catch.
Lord Tydus
2
FYI. Los procedimientos almacenados también son "código". El objetivo de los procesos almacenados era permitir mezclar código de procedimiento con SQL de estilo basado en conjuntos. Por lo tanto, tendrá una consulta en el código independientemente. Para aplicaciones de volumen extremadamente alto, a veces es mejor tener una lógica realizada fuera de la base de datos para permitir el escalado horizontal agregando servidores. Si puede mantener una única base de datos, pero muli-server para la lógica, la escala se vuelve mucho más fácil.
Lord Tydus
@GrandmasterB tenemos una cantidad sustancial de SQL en línea en C # (nuestro C # LOC ahora está cerca de 2 millones), y 6 años después volverá a mordernos porque ahora tenemos que buscar ese SQL en línea (recientemente contratamos a un experto en SQL) - Así que estamos haciendo ajustes de rendimiento). Confía en mí: nunca sabes qué tan grande será tu aplicación y cómo cambiarán las cosas en el futuro. Mantenga diferentes idiomas en diferentes archivos, incluso si simplemente lo delega en recursos de manifiesto. También podría // SQLCODEhacerlo, pero debe recordar hacer eso.
Jonathan Dickinson el
1
@ JonathanDickinson, use los procedimientos almacenados si lo desea. He dicho muchas veces que son útiles cuando tiene bases de código dispares que operan en la misma base de datos. Pero el hecho de que sean útiles en algunas circunstancias no hace que no se use automáticamente como 'mala práctica' todo el tiempo . Si el uso de instrucciones SQL directamente no está causando un problema, entonces no es una 'mala práctica' para esa aplicación.
GrandmasterB

Respuestas:

10

El uso de procedimientos almacenados es unidireccional y se ha utilizado ampliamente durante muchos años.

Una forma más moderna de interactuar con las bases de datos de SQL Server desde C # (o cualquier lenguaje .NET) es usar Entity Framework. La ventaja de Entity Framework es que proporciona un mayor nivel de abstracción.

Para citar de Microsoft ( https://msdn.microsoft.com/en-us/data/jj590134 ):

ADO.NET Entity Framework permite a los desarrolladores crear aplicaciones de acceso a datos mediante la programación contra un modelo de aplicación conceptual en lugar de programar directamente contra un esquema de almacenamiento relacional. El objetivo es disminuir la cantidad de código y mantenimiento necesarios para las aplicaciones orientadas a datos. Las aplicaciones de Entity Framework brindan los siguientes beneficios:

  • Las aplicaciones pueden funcionar en términos de un modelo conceptual más centrado en la aplicación, incluidos los tipos con herencia, miembros complejos y relaciones.
  • Las aplicaciones están libres de dependencias codificadas en un motor de datos o esquema de almacenamiento en particular.
  • Las asignaciones entre el modelo conceptual y el esquema específico de almacenamiento pueden cambiar sin cambiar el código de la aplicación.
  • Los desarrolladores pueden trabajar con un modelo de objeto de aplicación consistente que se pueda asignar a varios esquemas de almacenamiento, posiblemente implementados en diferentes sistemas de administración de bases de datos.
  • Se pueden asignar varios modelos conceptuales a un único esquema de almacenamiento.
  • El soporte de consulta integrada en el lenguaje (LINQ) proporciona validación de sintaxis en tiempo de compilación para consultas contra un modelo conceptual.

El uso de un ORM vs Procedimientos almacenados implica compensaciones, particularmente en términos de seguridad y dónde reside la lógica.

El enfoque "clásico" para el desarrollo con SQL Server es hacer que la lógica de la aplicación resida en procedimientos almacenados y programas que solo tengan derechos de seguridad para ejecutar procedimientos almacenados, no actualizar tablas directamente. El concepto aquí es que los procedimientos almacenados son la capa de lógica de negocios para las aplicaciones. Si bien la teoría es sólida, ha tendido a caer en desgracia por varias razones, siendo reemplazada por la implementación de la lógica de negocios en un lenguaje de programación como C # o VB. Las buenas aplicaciones aún se implementan con un enfoque escalonado, incluida la separación de preocupaciones, etc., pero es más probable que sigan un patrón como MVC.

Una desventaja de implementar la lógica en el ORM en lugar de en la base de datos es la facilidad de depuración y prueba de las reglas de integridad de datos por parte de los responsables de la base de datos (DA o DBA). Tome el ejemplo clásico de transferir dinero de su cuenta corriente a su cuenta de ahorros, es importante que esto se haga como una unidad atómica de trabajo, en otras palabras, intercalado en una transacción. Si este tipo de transferencia solo se puede realizar a través de un procedimiento almacenado, es relativamente fácil para el DA y los auditores QA el procedimiento almacenado.

Si, por otro lado, esto se hace a través de un ORM como Entity Framework y en la producción se descubre que en raras ocasiones se extrae dinero de la verificación pero no se deposita en la depuración de ahorros puede ser mucho más complejo, particularmente si múltiples programas están potencialmente involucrados. Es muy probable que este sea un caso extremo, que tal vez implique problemas de hardware peculiares que deben ocurrir en una secuencia particular, etc. ¿Cómo se prueba esto?

JonnyBoats
fuente
U otro ORM. Hay muchos de ellos, con varias ventajas y desventajas en comparación con EF.
svick
8
Listar las desventajas de los ORM haría esta respuesta más útil.
Den el
6

En realidad, la afirmación básica es discutible: existen compensaciones de cualquier manera entre tener SQL en el código o tener código en la base de datos (que es a donde se dirige con los procedimientos almacenados).

El resultado de esto es que no existe un "mejor" único, esto no es algo que pueda generalizar porque, sea cual sea el camino que tome, se compromete (obtiene beneficios pero también introduce restricciones).

Si hay una correspondencia uno a uno entre su aplicación y su base de datos, entonces realmente no importa. Si, por otro lado, tiene una gran base de datos central compartida por un número significativo de aplicaciones, la aplicación de la coherencia dentro de la base de datos entre esas aplicaciones se vuelve mucho más importante.

Lo que es más importante es preocuparse por la arquitectura y las capas de su aplicación: dada una capa de acceso a datos adecuada, ya sea que use un ORM como Entity Framework o NHibernate o haga algo más directo, debe aislar la mayor parte de su aplicación de esta decisión, independientemente de si crea consultas o usar procedimientos almacenados.


Con toda libertad tendré a trabajar en proyectos relativamente pequeños con equipos pequeños (1-3 desarrolladores): el uso de procedimientos almacenados es, para mí, más problemático de lo que vale porque dada la naturaleza de nuestras aplicaciones (¿y mi conjunto de habilidades?) el código es generalmente mucho más fácil que actualizar el esquema (incluso permitiendo que tenga un código que hace que la actualización del esquema sea relativamente sencilla) y puedo hacer cumplir las reglas comerciales mediante el uso de un código de acceso a datos común. Este es claramente un ejemplo clásico de "Su millaje puede variar".

Murph
fuente
2
+1 para "no es el mejor", -1 para implementar código es más fácil que implementar cambios de proceso almacenados, +1 para elegir un enfoque que tenga sentido para su aplicación y garantice el aislamiento DAL - Entonces +1.
Joel Brown
Califiqué el bit de implementación con "para mí" porque ese ha sido el caso para mí (especialmente para las aplicaciones web), por todo lo que podría tener un poco de reescritura en esa área.
Murph
+1, lo mejor depende de la aplicación y la situación.
GrandmasterB
1
Supongo que depende de las condiciones en las que trabaje. Si no tiene DBA que lo bloqueen de la producción, colocar un proceso almacenado de reemplazo en la base de datos puede ser terriblemente fácil. Para el caso, sin controles de producción que suelten nuevas marcas, secuencias de comandos e incluso nuevos códigos compilados en una aplicación centralizada también puede ser demasiado fácil.
Joel Brown
@JoelBrown - Exactamente - Supongo que no, estoy seguro de que hice un montón de suposiciones allí. En primer lugar, mi esquema está controlado por la versión (de manera cruda pero efectiva), no soy dba, pero soy lo suficientemente inteligente como para saber que el esquema de uno debe ser coherente. Trabajo principalmente en aplicaciones web y no puede acceder a las bases de datos, excepto visitando el servidor, mientras que (solo) reduje la implementación de aplicaciones a (más o menos) un solo clic de botón ... integrando actualizaciones de esquema en dicho la implementación está en la lista, pero siempre he encontrado que las actualizaciones de esquemas son más estresantes que las actualizaciones de código (¿facilidad de reversión?)
Murph
4

Mientras haya parametrizado sus entradas, cualquier enfoque es válido. Gran parte de las consultas de no tener argumentos en el código provienen de los viejos tiempos, cuando muchas de las bibliotecas lo forzaron a unir sus declaraciones en cadena y de ahí provienen los ataques de inyección SQL.

Cuenta
fuente
1
¿Es suficiente la parametrización? ¿No necesitas desinfectar también?
StuperUser
eso depende de su fuente y su propósito. Estaba tomando su pregunta literalmente, él es de solo lectura con algunos parámetros. en casos comunes, lo peor que haría con una entrada sucia si se parametriza correctamente es obtener una excepción de tipo o ningún resultado con una entrada incorrecta. La inserción es diferente y generalmente necesita validación a menos que trate la fuente como autoritativa.
Bill el
0

La mejor práctica es realmente exagerada aquí: hay muchas buenas maneras de hacerlo y la que elija realmente debería depender de cuál es su aplicación y qué debe hacer. Dicho esto, solo hay dos cosas que puedes hacer realmente mal:

  • Como señala @Bill, siempre debe parametrizar sus consultas. La creación de cadenas es un vector fácil para la inyección de SQL, así como todo tipo de errores difíciles de rastrear. Mucha gente más inteligente descubrió cómo tupelizar y escapar de sql, por lo que no es necesario que lo descubras tú mismo.

  • Cierra tus conexiones. La mejor manera es envolver todo con una declaración de uso, pero intentar / atrapar / finalmente también es genial si eso flota tu bote. Pero siempre asegúrese de usar una conexión como un automóvil barato: conduzca con fuerza y ​​rapidez y deshágase de él rápidamente.

La otra práctica por la que argumentaría vehementemente es que debe asegurarse de concentrar su código de acceso a datos en la menor cantidad de lugares posible. No permitimos que las aplicaciones web front-end tengan una referencia directa a System.Data.SqlClient para ayudar a hacer cumplir esta advertencia.

Wyatt Barnett
fuente