Sé que hay mucho escrito respecto las mejores prácticas de ADO.NET, sin embargo quise resumir las buenas prácticas según mi experiencia.
Esta es la primera y más recomendada practica, empecemos abriendo y cerrando conexiones, a continuación un ejemplo en código.
1. public static int GetProductCount()
2. {
3. string sql = "SELECT COUNT(*) " +
4. "FROM Production.Product " +
5. "WHERE ListPrice > 0";
6. object dbValue;
7.
8. using (SqlConnection connection = ConnectionManager.GetConnection())
9. {
10. using (SqlCommand command = new SqlCommand(sql, connection))
11. {
12. command.CommandType = CommandType.Text;
13. dbValue = command.ExecuteScalar();
14. }
15. }
16.
17. return (int)dbValue;
18. }
La línea de código 8 es clave, ConnectionManager es una clase que se encarga de administrar las conexiones (una clase propia, no pertenece a ADO.NET) esta clase contiene un método GetConnection que devuelve una conexión abierta.
La instrucción using provee una conveniente sintaxis que asegura el correcto uso de los objetos IDisposable, por lo que es ideal para aplicar esta buena práctica. Expliquémosla brevemente.
Cuando se crea una instancia dentro de la instrucción using, como en la línea 8 y 10, se asegura que el método Dispose es llamado sobre el objeto cuando el bloque de using termina, o cuando ocurre una excepción, la clase de la cual nace el objeto en cuestión debe implementar System.IDisposable (tanto SqlConnection como SqlCommand lo implementan).
Por tanto en la línea de código 15 se invoca el método Dispose de la conexión, Dispose y Close son funcionalmente equivalentes.
Ahora apliquemos el concepto en las consultas a datos con el sqlDataReader, es especialmente importante la práctica de cerrar en este caso.
1.//clase de la capa intermedia, que contiene un metodo de negocio que devuelve un data reader.
2. public class MyProductsDAC
3. {
4. public static SqlDataReader GetProductReader()
5. {
6. SqlConnection connection = new SqlConnection(aConnectionString);
7. connection.Open();
8. string sql = "SELECT Name, ListPrice FROM Production.Product";
9. SqlDataReader reader;
13. reader = command.ExecuteReader(CommandBehavior.SingleResult | CommandBehavior.CloseConnection);
14. } // Dispose command object.
15. return reader;
16. }
17. }
18.// Componente de interfaz de usuario, que llama al metodo de negocio de la capa intermedia.
19. public class MyUserInterfaceComponent
20. {
21. public void MyMethod()
22. {
23. using (SqlDataReader reader = MyProductsDAC.GetProductReader())
24. {
25. while (reader.Read())
26. {
27. Console.WriteLine("Product name: {0}", reader.GetString(0));
28. Console.WriteLine("Product price: {0}", reader.GetDecimal(1));
29. }
30. }
31. // Se invoca el Dispose del data reader, el cual cierra la conexión.
32. }
33. }
La línea de código 23 es clave, en esta línea se hace el llamado al método GetProductReader que retorna un sqlDataReader con datos. Nuevamente como este objeto es creado dentro del contexto de using al finalizar el bloque se ejecuta el Dispose del objeto el cual cierra la conexión.
Las conexiones son recursos caros desde el punto de vista de la performance, por tanto hay que hacer un manejo cuidadoso de él. Asegurarse de cerrar las conexiones cuando no se utilizan permite devolverlas al pool de conexiones disponibles para ser reutilizadas.