Saltar al contenido

¿Cómo puedo convertir fácilmente DataReader a List??

Este dilema se puede solucionar de diversas maneras, pero nosotros te dejamos la que para nosotros es la solución más completa.

Solución:

Sugeriría escribir un método de extensión para esto:

public static IEnumerable Select(this IDataReader reader,
                                       Func projection)

    while (reader.Read())
    
        yield return projection(reader);
    

A continuación, puede utilizar LINQ ToList() método para convertir eso en un List si quieres, así:

using (IDataReader reader = ...)

    List customers = reader.Select(r => new Customer 
        CustomerId = r["id"] is DBNull ? null : r["id"].ToString(),
        CustomerName = r["name"] is DBNull ? null : r["name"].ToString() 
    ).ToList();

De hecho, sugeriría poner un FromDataReader método en Customer (o en otra parte):

public static Customer FromDataReader(IDataReader reader)  ... 

Eso dejaría:

using (IDataReader reader = ...)

    List customers = reader.Select(Customer.FromDataReader)
                                     .ToList();

(Yo no pensar la inferencia de tipos funcionaría en este caso, pero podría estar equivocado…)

He escrito el siguiente método usando este caso.

Primero, agregue el espacio de nombres: System.Reflection

Por ejemplo: T es el tipo de retorno (ClassName) y dr es parámetro para el mapeo DataReader

C#, método de mapeo de llamadas como el siguiente:

List personList = new List();
personList = DataReaderMapToList(dataReaderForPerson);

Este es el método de mapeo:

public static List DataReaderMapToList(IDataReader dr)

    List list = new List();
    T obj = default(T);
    while (dr.Read()) 
        obj = Activator.CreateInstance();
        foreach (PropertyInfo prop in obj.GetType().GetProperties()) 
            if (!object.Equals(dr[prop.Name], DBNull.Value)) 
                prop.SetValue(obj, dr[prop.Name], null);
            
        
        list.Add(obj);
    
    return list;

VB.NET, método de mapeo de llamadas como el siguiente:

Dim personList As New List(Of Person)
personList = DataReaderMapToList(Of Person)(dataReaderForPerson)

Este es el método de mapeo:

Public Shared Function DataReaderMapToList(Of T)(ByVal dr As IDataReader) As List(Of T)
        Dim list As New List(Of T)
        Dim obj As T
        While dr.Read()
            obj = Activator.CreateInstance(Of T)()
            For Each prop As PropertyInfo In obj.GetType().GetProperties()
                If Not Object.Equals(dr(prop.Name), DBNull.Value) Then
                    prop.SetValue(obj, dr(prop.Name), Nothing)
                End If
            Next
            list.Add(obj)
        End While
        Return list
    End Function

He visto sistemas que usan Reflection y attributes en Propiedades o campos para asignar DataReaders a objetos. (Un poco como lo que hace LinqToSql). Ahorran un poco de escritura y pueden reducir la cantidad de errores al codificar para DBNull, etc. Una vez que almacena en caché el código generado, pueden ser más rápidos que la mayoría del código escrito a mano, así considerar el “camino alto” si está haciendo esto mucho.

Consulte “Una defensa de la reflexión en .NET” para ver un ejemplo de esto.

A continuación, puede escribir código como

class CustomerDTO  

    [Field("id")]
    public int? CustomerId;

    [Field("name")]
    public string CustomerName;

using (DataReader reader = ...)
    
   List customers = reader.AutoMap()
                                    .ToList();

(AutoMap(), es un método de extensión)


@Stilgar, gracias por un estupendo comentario

si son capaz de es probable que sea mejor usar NHibernate, EF o Linq to Sql, etc. Sin embargo, en un proyecto antiguo (o por otras razones (a veces válidas), por ejemplo, “no inventado aquí”, “amor por los procesos almacenados”, etc.) No siempre es es posible usar un ORM, por lo que un sistema más liviano puede ser útil para tener “bajo la manga”

Si también necesitaba escribir muchos bucles de IDataReader, verá el beneficio de reducir la codificación (y los errores) sin tener que cambiar la arquitectura del sistema en el que está trabajando. Eso no quiere decir que sea una buena arquitectura para empezar.

Supongo que CustomerDTO no saldrá de la capa de acceso a datos y los objetos compuestos, etc. serán construidos por la capa de acceso a datos utilizando los objetos DTO.


Unos años después de que escribí esta respuesta, Dapper ingresó al mundo de .NET, es probable que sea un muy buen punto de partida para escribir su propio AutoMapper, tal vez elimine por completo la necesidad de que lo haga.

Reseñas y valoraciones del post

Nos puedes corroborar nuestro estudio poniendo un comentario y puntuándolo te estamos eternamente agradecidos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *