2011-06-09 59 views
5

Estoy buscando una solución para saber cómo extraer datos de una base de datos al usar un DataRow y un DataReader con una sola función (o una función base).Extracto de DataRow o DataReader con una función

Mi problema surge del hecho de que a veces necesito un DataReader y a veces necesito una DataTable/DataRow pero luego para extraer los datos de esos objetos necesito dos métodos de acceso a datos separados porque no comparten una interfaz.

Básicamente, cuando mis estructura de base de los cambios, no quiero tener que entrar y escribir el siguiente código de recuperación de datos en múltiples funciones:

someValue = dr["someValue"] 

Es la misma sintaxis y hace lo mismo por lo que quiero una función que comparta esa funcionalidad, independientemente de si estoy usando un DataReader o DataTable/DataRow para extraer los datos de la base de datos.

Respuesta

5

Puede utilizar CreateDataReader método en la clase DataTable a acceder a los datos a través de la clase base DbDataReader. Por lo tanto, puede cambiar la implementación pero mantener el mapeo.

public List<MyType> GetMyTypeCollection(DbDataReader reader) 
{ 
//mapping code here 
} 

Sería mejor si puede pasar a un ORM donde no tiene que mapear manualmente.

Tome un vistazo a este micro ORM Dapper

+0

¡Gracias, esto es exactamente lo que necesitaba!No tenía idea de que el método existía. – Nate32

2

Uso this artículo para convertir el datareader a una tabla de datos y luego se puede interactuar tanto como una tabla de datos

Así que, básicamente, agregar esta función que consiguen que se llama desde su capa de datos:

public DataTable ConvertDataReader(SqlDataReader dr) 
{ 
    SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection); 
    DataTable dtSchema = dr.GetSchemaTable(); 
    DataTable dt = new DataTable(); 

    // You can also use an ArrayList instead of List<> 
    List<DataColumn> listCols = new List<DataColumn>();    
    if(dtSchema != null) 
    { 
    foreach (DataRow drow in dtSchema.Rows) 
    { 
     string columnName = System.Convert.ToString(drow["ColumnName"]); 
     DataColumn column = new DataColumn(columnName, 
           (Type)(drow["DataType"])); 
     column.Unique = (bool)drow["IsUnique"]; 
     column.AllowDBNull = (bool)drow["AllowDBNull"]; 
     column.AutoIncrement = (bool)drow["IsAutoIncrement"]; 
     listCols.Add(column); 
     dt.Columns.Add(column); 
    } 
    } 

    // Read rows from DataReader and populate the DataTable 
    while (dr.Read()) 
    { 
    DataRow dataRow = dt.NewRow(); 
    for(int i = 0; i < listCols.Count; i++) 
    { 
     dataRow[((DataColumn)listCols[i])] = dr[i]; 
    } 
    dt.Rows.Add(dataRow); 
    } 
} 

Y luego en su función donde obtiene la tabla de datos, entonces haría un si es un lector de datos, pase el lector a la función para devolver una tabla de datos:

DataTable dtFromReader = ConvertDataReader(dr); 
0

Crear un adaptador para ocultar la ejecución de DataReader trabajar con códigos DataTable/DataRow

1

¿Se refiere a la fila de automóviles sql mapa del resultado de la consulta a una entidad? ¿Me gusta esto?

public static List<T> ToList<T>(this IDataReader idr, int count) where T : new() 
{ 
    if (idr == null) 
     throw new ArgumentNullException("idr"); 

    if (idr.IsClosed) 
     throw new ArgumentException("IDataReader is closed."); 

    Type businessEntityType = typeof(T); 
    List<T> entitys = new List<T>(); 
    Hashtable hashtable = new Hashtable(); 
    PropertyInfo[] properties = businessEntityType.GetProperties(); 

    int idx = 0; 

    foreach (PropertyInfo info in properties) 
    { 
     hashtable[info.Name.ToUpper()] = info; 
    } 

    while (idr.Read()) 
    { 
     if (count > 0) 
      idx++; 

     T newObject = new T(); 
     for (int index = 0; index < idr.FieldCount; index++) 
     { 
      PropertyInfo info = (PropertyInfo)hashtable[idr.GetName(index).ToUpper()]; 
      if (info != null && info.CanWrite) 
      { 
       try 
       { 
        info.SetValue(newObject, idr.GetValue(index), null); 
       } 
       catch 
       { 

       } 
      } 
     } 

     entitys.Add(newObject); 

     if (idx > count) 
      break; 
    } 
    return entitys; 
} 
+0

acciones de Db tiene un costo. Agregue reflejo, va a ser notablemente más lento. Debe confiar en árboles de expresión en lugar de reflexión. Consulte esta respuesta http://stackoverflow.com/a/19845980/661933 para, p. Ej. Y haga uso de genéricos (utilice el diccionario en lugar de hashtable) – nawfal

0

Como solución alternativa que utiliza una función privada que tuvo un argumento dinámico. Luego se agregaron dos funciones públicas que tomaron los argumentos "DataRow" y "DataReader". Puede usar esto para limitar las llamadas a tipos o interfaces conocidos.

public MyResults DoStuff(DataRow dr) 
{ 
    return ActualDoStuff(dr); 
} 

public MyResults DoStuff(DataReader dr) //IDataRecord is better if just reading 
{ 
    return ActualDoStuff(dr); 
} 

private MyResults ActualDoStuff(dynamic dr) 
{ 
    var rez = new MyResults(); 
    rez.someValue = dr["someValue"]; 
    return rez; 
} 

Una palabra de advertencia. Es posible que deba volver a escribir su código de carga ligeramente, ya que el comportamiento del contenido de dr al que se accede mediante cadena en una dinámica es ligeramente diferente. Es decir.

if(dr["someValue"] == DBNull.Value) 

podría ser necesario cambiar a

if(dr["someValue"] is DBNull) 

Pero este enfoque todavía evita el problema de código de carga duplicada.