Creando un Wrapper para Data Access Application Blocks

Son varias las aplicaciones donde utilizamos DataSet tipados o no y siempre es un poco tedioso estar generando las sentecias CRUD respectivas para cada DataSet, por eso me he decidido a crear un Wrapper para DAAB de las Enterprise Library que encapsule esta funcionalidad y automatice el proceso de actualización de la base de datos. A continuación os muestro el código;

1. Cargamos el DataSet:

public void FillDataSet(DataSet dsInfo, string sql, string [] tablas)
{
    _db.LoadDataSet(CommandType.Text,
                    sql,
                    dsInfo,
                    tablas);
}
2. Creamos la función que actualizará la base de datos:
public void UpdateDataSet(DataSet dsInfo)
{
    DbCommand insertCommand = null;
    DbCommand insertCommandParameters = null;
    DbCommand deleteCommand = null;
    DbCommand deleteCommandParameters = null;
    DbCommand updateCommand = null;
    DbCommand updateCommandParameters = null;

    StringBuilder sbConstructor1 = new StringBuilder();
    StringBuilder sbConstructor2 = new StringBuilder();
    StringBuilder sbConstructor3 = new StringBuilder();

    string sSQLInsert = "INSERT INTO {0} VALUES ({1})";
    string sSQLUpdate = "UPDATE {0} SET {1} WHERE {2}";
    string sSQLDelete = "DELETE FROM {0} WHERE {1}";

    foreach (DataTable dtTable in dsInfo.Tables)
    {
        ArrayList arrLstPrimaryKeys = new ArrayList(dtTable.PrimaryKey);

        if (arrLstPrimaryKeys.Count < 1)
        {
            throw new Exception(String.Format("Table: {0} not contains Primary Keys", dtTable.TableName));
        }

        insertCommandParameters = _db.GetSqlStringCommand(sSQLInsert);
        deleteCommandParameters = _db.GetSqlStringCommand(sSQLDelete);
        updateCommandParameters = _db.GetSqlStringCommand(sSQLUpdate);

        foreach (DataColumn dtColumn in dsInfo.Tables[dtTable.TableName].Columns)
        {
            _db.AddInParameter(insertCommandParameters, dtColumn.ColumnName, GetDbType(dtColumn.DataType.ToString()), dtColumn.ColumnName, DataRowVersion.Current);
            _db.AddInParameter(deleteCommandParameters, dtColumn.ColumnName, GetDbType(dtColumn.DataType.ToString()), dtColumn.ColumnName, DataRowVersion.Current);
            _db.AddInParameter(updateCommandParameters, dtColumn.ColumnName, GetDbType(dtColumn.DataType.ToString()), dtColumn.ColumnName, DataRowVersion.Current);

            sbConstructor1.Append(String.Format("@{0},", dtColumn.ColumnName));

            if (arrLstPrimaryKeys.Contains(dtColumn))
            {
                sbConstructor2.Append(String.Format("{0} = @{1},",
                                                    dtColumn.ColumnName,
                                                    dtColumn.ColumnName));
            }
            else
            {
                sbConstructor3.Append(String.Format("{0} = @{1},",
                                                    dtColumn.ColumnName,
                                                    dtColumn.ColumnName));
            }
        }
        sSQLInsert = String.Format(sSQLInsert, dtTable.TableName,
                                         sbConstructor1.ToString().Substring(0, sbConstructor1.Length - 1));

        sSQLDelete = String.Format(sSQLDelete, dtTable.TableName,
                                         sbConstructor2.ToString().Substring(0, sbConstructor2.Length - 1));

        sSQLUpdate = String.Format(sSQLUpdate, dtTable.TableName,
                                         sbConstructor3.ToString().Substring(0, sbConstructor3.Length - 1),
                                         sbConstructor2.ToString().Substring(0, sbConstructor2.Length - 1));

        insertCommand = _db.GetSqlStringCommand(sSQLInsert);
        SetParameters(ref insertCommand, ref insertCommandParameters);

        deleteCommand = _db.GetSqlStringCommand(sSQLDelete);
        SetParameters(ref deleteCommand, ref deleteCommandParameters);

        updateCommand = _db.GetSqlStringCommand(sSQLUpdate);
        SetParameters(ref updateCommand, ref updateCommandParameters);

        int rowsAffected = _db.UpdateDataSet(dsInfo,
                                             dtTable.TableName,
                                             insertCommand,
                                             updateCommand,
                                             deleteCommand,
                                             UpdateBehavior.Transactional);
    }
}


Muchos os preguntaréis: ¿Por qué utiliza 6 comandos? ¿Está loco?, bien la explicación es sencilla:

Como la Query se va creando dinámicamente, hasta el final no tengo disponible todos los parámetros que formarán la query, entonces sino utilizase esos comandos auxiliares la colección de parametros estaría vacía puesto que al llamar al método GetSqlStringCommand con la sentencia sin parámetros no sabrá los que tiene. Entonces pensé, sino utilizo comandos auxiliares tendré que hacer otro bucle para sacar nuevamente los parámetros, simplemente por eso (Espero haberme explicado)

3. Crear un método que pase los parámetros del comando auxiliar al principal:

private void SetParameters(DbCommand command, DbCommand command2)
{
    ArrayList arrLstParameters = new ArrayList(command2.Parameters);
    command2.Parameters.Clear();
    command.Parameters.AddRange(arrLstParameters.ToArray());
}

4. Crear un método que nos convierta los tipos de Datos de .NET (System.) a los tipos SQL System.Data

private DbType GetDbType(string stype)
{
    switch (stype)
    {
        case "System.String":
            return DbType.String;
        case "System.Int16":
            return DbType.Int16;
        case "System.Int32":
            return DbType.Int32;
        case "System.Int64":
            return DbType.Int64;
        case "System.UInt16":
            return DbType.UInt16;
        case "System.UInt32":
            return DbType.UInt32;
        case "System.UInt64":
            return DbType.UInt64;
        case "System.Decimal":
            return DbType.Decimal;
        case "System.Double":
            return DbType.Double;
        case "System.DateTime":
            return DbType.DateTime;
        case "System.Guid":
            return DbType.Guid;
        case "System.Boolean":
            return DbType.Boolean;
        case "System.Byte":
            return DbType.Byte;
        case "System.SByte[]":
            return DbType.Binary;
        case "System.SByte":
            return DbType.SByte;
        case "System.Single":
            return DbType.Single;
        case "System.Object":
            return DbType.Object;
        default:
            return DbType.Object;
    }
}


Y con esto estaría todo listo, pero para DataSet no tipados necesitáis crear la primary key antes de llamara la método UpdateDataset ó saltará la excepción diciendo que no existe clave primaria.

Seguro que este código se puede mejorar, por eso lo he posteado, para que entre todos los que se apunten podamos crear una librería para reutilizarla en nuestras aplicaciones.

Espero muchas críticas, porque eso significará que os interesa.

Código
Script de la base de datos

Salu2.

Published 30/10/2006 19:44 por Luis Ruiz Pavón
Archivado en:
Comparte este post:
http://geeks.ms/blogs/lruiz/archive/2006/10/30/Creando-un-Wrapper-para-Data-Access-Application-Block.aspx

Comentarios

# re: Creando un Wrapper para Data Access Application Blocks

Hola:

Es muy interesante. Pero si utilizamos procedimientos almacenados, ¿qué opinas del DataTierGenerator para la Enterprise Library (http://www.gotdotnet.com/workspaces/workspace.aspx?id=ec008788-3ad7-4d70-8c09-f496853e15c3) ?

Un saludo.

Tuesday, October 31, 2006 1:42 PM por pserranop

# re: Creando un Wrapper para Data Access Application Blocks

Si te digo la verdad todavía no había pensado en los procedimientos,está que tienes razón y que habría que pensar como desarrollar algún método para que en base al DataSet obtenga una serie de procedimeintos almacenados ya creados o en caso de no existir los cree y los utilice. La verdad es que esto se me ocurrió el otro día y solo había desarollado la parte que me hacía falta, pero poco a poco se irán implementado nuevas funcionalidades.

En cuanto a DataTierGenerator no la conocía. La echaré un vistazo.

Salu2.

Tuesday, October 31, 2006 2:14 PM por Luis Ruiz Pavón

# re: Creando un Wrapper para Data Access Application Blocks

no necesitas pasar los parametros como ref, es muy raro que se requiera el uso de ref

salu2

Saturday, December 23, 2006 3:19 AM por Eber Irigoyen

# re: Creando un Wrapper para Data Access Application Blocks

Wednesday, March 14, 2007 8:54 AM por Luis Ruiz Pavón

# re: Creando un Wrapper para Data Access Application Blocks

Hola,

d´´onde está el DataTierGenerator para la Enterprise Library  ??? está roto el enlace.

alguna novedad sobre sus ideas sr. Ruiz ??

gracias

Monday, November 02, 2009 4:32 PM por preguntoncojonero