Oct 13 2008

C# Ejecutar un procedimiento de almacenado (store procedure)

Category: ProgramacionIndigo @ 10:20 AM

Una característica de muchos gestores de bases de datos como Sql Server, es que permiten guardar las consultas para poder ejecutarlas desde nuestro código. Asi conseguimos abstraer nuestra lógica de datos de nuestra lógica de negocio. En Sql Server estas consultas se llaman procedimientos de almacenado. Un ejemplo de esto es

[sourcecode language='sql']SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE dbo.sp_test
– Add the parameters for the stored procedure here
@IdFoo int
AS
BEGIN
SELECT
*
FROM
Foo
WHERE
IdFoo = @IdFoo
END
GO[/sourcecode]

Este procedimiento recibe como parametro el entero @IdFoo, y busca en la tabla Foo, un registro que tenga el campo IdFoo igual al parametro de entrada @IdFoo. Para llamar este procedimiento de almacenado desde nuestro código tan sólo debemos hacer lo siguiente

[sourcecode language='csharp']public void ExecuteStoreProcedure(int idFoo)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand())
{
connection.Open();

command.Connection = connection;
command.CommandType = System.Data.CommandType.StoredProcedure;
command.CommandText = “sp_test”;
command.CommandTimeout = 10;

command.Parameters.AddWithValue(”@IdFoo”, idFoo);

SqlDataReader reader = command.ExecuteReader();
}
}
}[/sourcecode]

Como vemos es muy fácil, creamos una conexión, y un comando. A este comando le decimos que ejecutará el procedimiento sp_test y le pasamos el parametro idFoo como @IdFoo. El resultado de la consulta se guarda en un SqlDataReader. Ahora podremos recorrer este SqlDataReader para devolver algún dato o pasar la información a un objeto de negocio.

La principales ventajes de los procedimientos de almacenado son

  • Evita en parte los molestos ataques por inyección sql (sql injection).
  • La velocidad de la consulta es mayor.
  • Toda la logica de acceso a datos se encuentra en la base de datos.

Tags: , ,


Oct 10 2008

C# Ejecutar consulta sql

Category: ProgramacionIndigo @ 9:41 AM

Pese a que no recomiendo escribir las consultas sql en c# para luego lanzarlas contra nuestro gestor de base de datos, en algún momento no puede ser útil, sobre todo en la primeras fase de desarrollo. Para ejecutar una consulta sql tan solo debemos hacer lo siguiente

[sourcecode language='csharp']public void ExecuteSql(int idFoo)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand())
{
connection.Open();

command.Connection = connection;
command.CommandType = System.Data.CommandType.Text;
string sql = string.Format(”SELECT * FROM Foo WHERE IdFoo = {0}”, idFoo);
command.CommandText = sql;
command.CommandTimeout = 10;

SqlDataReader reader = command.ExecuteReader();
}
}
}[/sourcecode]

Como vemos es bastante fácil.

Tags: , ,


Oct 09 2008

C# El uso de transacciones con SqlTransaction

Category: ProgramacionIndigo @ 9:34 AM

¿Qué pasa si en alguna en un procesos de actualización de datos de una base de datos falla a la mitad? Lo normal en la mayoría de los casos es deshacer todo lo que se ha hecho y dejar la base de datos como estaba. Este proceso sería muy complicado hacerlo a mano, por no decir imposible. Para esto están las transacciones, que de una manera muy fácil nos ayudan a resolver este tipo de problemas.

Esta forma de trabajar con las bases de datos, podemos hacerlo desde nuestro código o directamente en la base de datos (en procedimientos de almacenado). En este artículo sólo explicaré como hacerlo desde nuestro código.

El código para utilizar una transacción es el siguiente

[sourcecode language='csharp']public void ExecuteTransaction()
{
// Usamos la clase SqlConnectionStringBuilder para construir la cadena de conexión
SqlConnectionStringBuilder _connectionStringBuilder = new SqlConnectionStringBuilder();
_connectionStringBuilder.DataSource = @”.\SQLEXPRESS”;
_connectionStringBuilder.InitialCatalog = “prueba”;
_connectionStringBuilder.IntegratedSecurity = true;

// Creamos la conexión
using(SqlConnection _connection = new SqlConnection(_connectionStringBuilder.ConnectionString))
{
// Abrimos la conexión
_connection.Open();

// Abrimos una transación en la conexión abierta
SqlTransaction _transaction = _connection.BeginTransaction();

// Creamos el objeto SqlCommand y asignamos los datos
// a los parámetros
SqlCommand _command = new SqlCommand();
_command.Connection = _connection;
_command.CommandType = CommandType.StoredProcedure;
_command.CommandText = “ProcedimientoAlmacenado”; // Aqui va el nombre del procedimiento de almacenado

// Añadimos los parametros
_command.Parameters.AddWithValue(”@Par1″, “Par1″);
_command.Parameters.AddWithValue(”@Par2″, “Par2″);

// Asignamos la transacción al comando
_command.Transaction = _transaction;

try
{
// Ejecutamos el comando
_command.ExecuteNonQuery();

// Si todo ha ido bien hacemos un “Commit” de la transacción
_transaction.Commit();
}
catch(Exception ex)
{
// Si se produce un error, desahacemos la transaccion (Rollback)
_transaction.Rollback();
}

// No se hace falta cerrar la conexión porque está dentro de un “using”
_connection.Close();
}
}[/sourcecode]

Lo primero que hacemos es crear una cadena de conexión y abrir una conexión con ésta. Con esta conexión abierta creamos la transacción (con el método “BeginTransaction”) y ejecutamos nuestro procedimiento de almacenado. Si todo ha ido bien, hacemos un “Commit” de la transacción y si algo ha fallado hacemos un “Rollback”. Es importante hacer un ”Commit” ya que si no, el sistema hará un “Rollback” automáticamente al cerrar la conexión.

Tal y como está el código sólo estamos haciendo una llamada la base de datos, pero modificando el código ligeramente podemos ver su verdadero potencial. Supongamos que tenemos la siguiente clase

[sourcecode language='csharp']public class Article
{
public int Id = 0;
public string Content = string.Empty;
}
[/sourcecode]

Y tenemos un método que recibe una lista de artículos que tenemos que actualizar. Este método creará una transacción y la utilizará para actualizar cada artículo. El código sería como este

[sourcecode language='csharp']public void UpdateArticles(List

articles)
{
SqlTransaction _transaction = CreateTransaction();
try
{
foreach (Article article in articles)
{
UpdateArticle(_transaction, article);
}
_transaction.Commit();
}
catch
{
_transaction.Rollback();
throw;
}

}

public void UpdateArticle(SqlTransaction transaction, Article article)
{
try
{
// Creamos el objeto SqlCommand y asignamos los datos
// a los parámetros
SqlCommand _command = new SqlCommand();
_command.Connection = transaction.Connection;
_command.CommandType = CommandType.StoredProcedure;
_command.CommandText = “UpdataArticle”; // Aqui va el nombre del procedimiento de almacenado

// Añadimos los parametros
_command.Parameters.AddWithValue(”@Id”, article.Id);
_command.Parameters.AddWithValue(”@Content”, article.Content);

// Asignamos la transacción al comando
_command.Transaction = transaction;

// Ejecutamos el comando
_command.ExecuteNonQuery();
}
catch
{
throw;
}
}

public SqlTransaction CreateTransaction()
{
try
{
// Usamos la clase SqlConnectionStringBuilder para construir la cadena de conexión
SqlConnectionStringBuilder _connectionStringBuilder = new SqlConnectionStringBuilder();
_connectionStringBuilder.DataSource = @”.\SQLEXPRESS”;
_connectionStringBuilder.InitialCatalog = “prueba”;
_connectionStringBuilder.IntegratedSecurity = true;

// Creamos la conexión
SqlConnection _connection = new SqlConnection(_connectionStringBuilder.ConnectionString);

// Abrimos la conexión
_connection.Open();

// Abrimos una transación en la conexión abierta
SqlTransaction _transaction = _connection.BeginTransaction();

return _transaction;
}
catch
{
throw;
}
}[/sourcecode]

Cómo hemos visto el uso de transacciones desde .NET es muy fácil y hace nuestras aplicaciones más robustas. Pero, ¿qué pasa cuando entran en juego varias bases de datos, o incluso varios gestores de base de datos (varios Sql Server)? Para eso tenemos el TransactionScope, que podemos ver en http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx, pero esto lo dejo para otro momento.

Tags: , , ,


Oct 08 2008

C# La instrucción using

Category: ProgramacionIndigo @ 1:40 PM

La palabra clave using se puede usar en dos contextos

  • Como directiva, cuando se utiliza para crear un alias para un espacio de nombres o para importar tipos definidos en otros espacios de nombres.
  • Como instrucción, cuando define un ámbito al final del cual el objeto se destruye.

En este caso nos interesa la segunda definición y lo vamos a utilizar a la hora de utilizar conexiones a nuestra base de datos. Veamos este ejemplo:

[sourcecode language='csharp']SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand(commandString, connection);
connection.Open();
command.ExecuteNonQuery();
connection.Close();[/sourcecode]

Como vemos es un código muy simple. Abrimos una conexión, creamos un comando y lo ejecutamos. Este código esta aparentemente bien, pero si lo miramos con detalle, vemos que el SqlConnection y SqlCommand no liberan los recursos que usan y esto puede ser un problema en entornos de producción compartidos. Para evitar mejorar esto usaremos el siguiente código:

[sourcecode language='csharp']using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand(commandString, connection))
{
connection.Open();
command.ExecuteNonQuery();
}
}[/sourcecode]

Aquí podemos ver que la conexión y el comando se crean dentro de un bloque using, que hará una llamada al método Dispose cuando finalice. También es importante sabe que cualquier excepción que se produzca será lanzada. El equivalente de este código sin usar using sería

[sourcecode language='csharp']SqlConnection connection = null;
SqlCommand command = null;

try
{
connection = new SqlConnection(connectionString);
command = new SqlCommand(commandString, connection);
connection.Open();
command.ExecuteNonQuery();
}
finally
{
if (command != null)
command.Dispose();
if (connection != null)
connection.Dispose();
}[/sourcecode]

Como vemos, cuesta muy poco mejorar nuestra forma de programar…

Tags: , , ,