sábado, 25 de julio de 2009

Insertar un registro en una base de datos SQL Server utilizando un Procedimiento Almacenado en Visual C#.

Para insertar un Registro en una Base de Datos SQL Server utilizando un Procedimiento Almacenado (que por supuesto debe haberse definido previamente en la Base de Datos), Visual C# necesita conocer:
1º. El objeto (registro) que desea insertarse en la Base de datos, con todos sus campos y valores, el cual puede haberse definido en una Clase (por ejemplo una Clase "Articulo"). Este Articulo (o la Clase que sea) se pasa como un tipo "object" (que aquí hemos llamado "obj").
2º. Que, efectivamente, se va a utilizar un Procedimiento Almacenado.
3º. El nombre del Procedimiento Almacenado.
4º. Los parámetros de dicho Procedimiento.

A su vez, para que Procedimiento Almacenado pueda ser ejecutado, Visual C# exige conocer de cada parámetro del Procedimiento:
1º. El nombre del parámetro.
2ª. El tipo de dato SQL.
3º. El valor del parámetro.

Para obtener toda esta información vamos a recurrir a "Reflexion", una de las características esenciales de Visual C#, recorriendo las "propiedades públicas" del objeto "obj" que se desea insertar en la Base de Datos.

Quizá lo más complejo sea obtener el tipo de dato SQL, ya que los tipos de datos utilizados por Visual C# no son equivalentes a los tipos de datos SQL Server y, por ello, será necesario realizar una conversión explícita y evitar un error en tiempo de ejecución.

Veamos como hacerlo paso a paso:


   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using System.Data;
   6:  using System.Data.SqlClient;
   7:  using System.Configuration;
   8:  using System.Reflection;
   9:   
  10:  namespace AccionBaseDatos
  11:  { 
  12:      public class Insertar
  13:      {
  14:          //Variable que se va a utilizar para las instrucciones "lock" cuando la Aplicación entre en un proceso crítico
  15:          private static string semaforo = string.Empty;
  16:   
  17:   
  18:          /// Inserta un registro en la Base de datos utilizando el Procedimiento Almacenado cuyo nombre recibe como parámetro de entrada.
  19:          /// Para obtener los parámetros del Procedimiento Almacenado habrá que leer los datos de los campos y sus valores que vienen definidos en el parámetro "obj" que es de tipo "object"
  20:          public bool GuardarRegistroConProcedimiento(IDbConnection idbConnect, string nomProcedimiento, object obj)
  21:          {
  22:              //Creamos el comando SQL con el nombre del Procedimieneto Almacenado:
  23:              SqlCommand sqlCmd = new SqlCommand(nomProcedimiento);
  24:              //Se llama al método que obtiene los parámetros que necesita el Procedimiento almacenado
  25:              sqlCmd = ObtenerParametrosDelObjeto(sqlCmd, obj);
  26:              //Le indicamos que el comando SQL es de tipo Procedimniento Almacenado
  27:              sqlCmd.CommandType = CommandType.StoredProcedure;
  28:   
  29:              return RealizarTransaccion(sqlCmd, idbConnect); //Se llama al método que realiza la inserción y devuelve true o false si la ha realizado o no
  30:          }
  31:   
  32:   
  33:   
  34:          /// Obtiene los parámetros que necesita el Procedimieneto Almacenado para poder ejecutarse a partir de las "propiedades públicas" del Objeto "obj"  que se van a obtener utilizando el método "GetProperties()"
  35:          public SqlCommand ObtenerParametrosDelObjeto(SqlCommand sqlComando, object obj)
  36:          {
  37:              SqlDbType sqlDbTipo;
  38:              string nombreCampo = string.Empty;
  39:              string typ = string.Empty;
  40:              object valor = null;
  41:   
  42:              //Para obtener las "propiedades públicas" del Objeto "obj" las recorremos utilizando un bucle "foreach" y el método "GetProperties()":
  43:              foreach (PropertyInfo propiedad in obj.GetType().GetProperties()) //El método GetProperties() devuelve la propiedad
  44:              {
  45:                  nombreCampo = propiedad.Name; //Obtenemos el nombre del campo que hemos hecho coincidir con el nombre de la propiedad
  46:                  typ = propiedad.PropertyType.Name; //Obtenemos el nombre del tipo de dato (nombre del tipo de dato que utiliza el Framework).
  47:                  //Para obtener el tipo de dato SQL llamamos al método que realiza la conversión de tipos:
  48:                  sqlDbTipo = ComprobarTipoDeDatoSql(typ);
  49:                  //Obtenemos el valor del campo a partir del valor de la propiedad pública del objeto:
  50:                  valor = propiedad.GetValue(obj, null); //Como las propiedades del objeto "obj" no están indizadas el segundo parámetro es null
  51:                  //Creamos una variable de tipo Parámetro SQL con el nombre el campo y el tipo de dato SQL:
  52:                  SqlParameter sqlParametro = new SqlParameter("@" + nombreCampo, sqlDbTipo);
  53:                  //Le asignamos el valor del campo obtenido del objeto "obj" al valor del parámetro:
  54:                  sqlParametro.Value = valor;
  55:                  //Añadimos el parámetro al comando SQL
  56:                  sqlComando.Parameters.Add(sqlParametro);
  57:              }
  58:              return sqlComando; //Devuelve el comando SQL con los parámetros obtenidos
  59:          }
  60:   
  61:   
  62:          /// Obtiene el tipo de dato SQL guardado en el parámetro "tipo"
  63:          public SqlDbType ComprobarTipoDeDatoSql(string tipo)
  64:          {
  65:              SqlDbType tipoDatoSql;
  66:   
  67:              if (tipo == "Int32")
  68:                  tipoDatoSql = SqlDbType.Int;
  69:              else if (tipo == "DateTime")
  70:                  tipoDatoSql = SqlDbType.DateTime;
  71:              else if (tipo == "String")
  72:                  tipoDatoSql = SqlDbType.NVarChar;
  73:              else if (tipo == "Float")
  74:                  tipoDatoSql = SqlDbType.Float;
  75:              else if (tipo == "Boolean")
  76:                  tipoDatoSql = SqlDbType.Bit;
  77:              else if (tipo == "Double")
  78:                  tipoDatoSql = SqlDbType.Real;
  79:              else if (tipo == "Decimal")
  80:                  tipoDatoSql = SqlDbType.Decimal;
  81:              else
  82:                  tipoDatoSql = SqlDbType.Variant;
  83:   
  84:              return tipoDatoSql; //Devuelve el tipo de dato SQL obtenido
  85:          }
  86:   
  87:   
  88:   
  89:   
  90:          /// Ejecuta un comando SQL en la base de datos utilizando el método "ExecuteNonQuery()"
  91:          private bool RealizarTransaccion(SqlCommand sqlCmd, IDbConnection idbConnect)
  92:          {
  93:              try
  94:              {
  95:                  lock (semaforo) //Con la instrucción "lock" se indica que el programa va a entrar en un punto crítico para evitar que se ejecuten simultáneamente otros subprocesos
  96:                  {
  97:                      if (idbConnect.State == ConnectionState.Closed) //Se comprueba el estado de la conexión. Si está cerrada vuelve a abrirse:
  98:                          idbConnect.Open();
  99:   
 100:                      sqlCmd.Connection = (SqlConnection)idbConnect; //Se inicializa el objeto SqlConnection con la propia conexión "idbConnect" indicando que la conexión es de tipo SQL
 101:                      int filas = sqlCmd.ExecuteNonQuery(); //Se ejecuta la instrucción SQL, devolviendo el número de columnas afectadas
 102:                      if (filas > 0)
 103:                          return true;
 104:                      else
 105:                          return false;
 106:                  }
 107:              }
 108:              catch (Exception)
 109:              {
 110:                  return false;
 111:              }
 112:              finally
 113:              {//Se cierra la conexión
 114:                  if (idbConnect.State == ConnectionState.Open)
 115:                      idbConnect.Close();
 116:              }
 117:          }
 118:      }
 119:  }

No hay comentarios:

Publicar un comentario

Webs amigas:
Eduardo Soriano
Solcan
Taller de Joyería