Convert rows from a data reader into typed results

后端 未结 10 2129
醉梦人生
醉梦人生 2020-11-27 11:53

I\'m using a third party library which returns a data reader. I would like a simple way and as generic as possible to convert it into a List of objects.
For example, say

相关标签:
10条回答
  • 2020-11-27 12:34

    My version

    Usage:

    var Q = await Reader.GetTable<DbRoom>("SELECT id, name FROM rooms");
    

    PgRoom is

    public class DbRoom
    {
        [Column("id")]
        public int Id { get; set; }
    
        [Column("name")]
        public string Name { get; set; }
    }
    

    Reader.GetTable contains:

                using (var R = await Q.ExecuteReaderAsync())
                {
                    List<T> Result = new List<T>();
    
                    Dictionary<int, PropertyInfo> Props = new Dictionary<int, PropertyInfo>();
    
                    foreach (var p in typeof(T).GetProperties())
                    {
                        for (int i = 0; i < R.FieldCount; i++)
                        {
                            if (p.GetCustomAttributes<ColumnAttribute>().FirstOrDefault(t => t.Name == R.GetName(i)) != null
                                && p.PropertyType == R.GetFieldType(i))
                            {
                                Props.Add(i, p);
                            }
                        }
                    }
    
                    while (await R.ReadAsync())
                    {
                        T row = new T();
    
                        foreach (var kvp in Props)
                        {
                            kvp.Value.SetValue(row, R[kvp.Key]);
                        }
    
                        Result.Add(row);
                    }
    
                    return Result;
                }
    
    0 讨论(0)
  • 2020-11-27 12:35

    For .NET Core 2.0:

    Here is an extension method that works with .NET CORE 2.0 to execute RAW SQL and map results to LIST of arbitrary types:

    USAGE:

     var theViewModel = new List();
     string theQuery = @"SELECT * FROM dbo.Something";
     theViewModel = DataSQLHelper.ExecSQL(theQuery,_context);
    
     using Microsoft.EntityFrameworkCore;
     using System.Data;
     using System.Data.SqlClient;
     using System.Reflection;
    
    public static List ExecSQL(string query, myDBcontext context)
     {
     using (context)
     {
     using (var command = context.Database.GetDbConnection().CreateCommand())
     {
     command.CommandText = query;
     command.CommandType = CommandType.Text;
     context.Database.OpenConnection();
                    using (var result = command.ExecuteReader())
                    {
                        List<T> list = new List<T>();
                        T obj = default(T);
                        while (result.Read())
                        {
                            obj = Activator.CreateInstance<T>();
                            foreach (PropertyInfo prop in obj.GetType().GetProperties())
                            {
                                if (!object.Equals(result[prop.Name], DBNull.Value))
                                {
                                    prop.SetValue(obj, result[prop.Name], null);
                                }
                            }
                            list.Add(obj);
                        }
                        return list;
    
                    }
                }
            }
        }
    
    0 讨论(0)
  • 2020-11-27 12:39

    I found this solution.

    var cmd = ctx.Connection.CreateCommand();
    
    T result = DbDataReaderdHelper.Fill<T>(cmd)
    
    public static class DbDataReaderdHelper
    {
        public static List<T> Fill<T>(DbCommand dbCommand) where T : new()
        {
            List<T> result = new List<T>();
            var reader = dbCommand.ExecuteReader();
    
            if (reader.HasRows)
            {
                while (reader.Read())
                {
                    Type type = typeof(T);
                    T obj = (T)Activator.CreateInstance(type);
                    PropertyInfo[] properties = type.GetProperties();
    
                    foreach (PropertyInfo property in properties)
                    {
                        var value = reader[property.Name];
    
                        try
                        {
                            if (value != null)
                            {
                                var convertedValue = TypeDescriptor.GetConverter(property.PropertyType).ConvertFromInvariantString(value.ToString());
    
                                property.SetValue(obj, convertedValue);
                            }
                        }
                        catch {}
                    }
                    result.Add(obj);
                }
            }
    
            reader.Close();
    
            return result;
        }
    }
    
    0 讨论(0)
  • 2020-11-27 12:47

    Like Magic

    I personally HATE doing manual mapping in constructors, I'm also not a fan of doing my own reflection. So here's another solution courtesy of the wonderful (and fairly ubiquitous) Newtonsoft JSON lib.

    It will only work if your property names exactly match the datareader column names, but it worked well for us.

    ...assumes you've got a datareader name "yourDataReader"...

            var dt = new DataTable();
            dt.Load(yourDataReader);
            // creates a json array of objects
            string json = Newtonsoft.Json.JsonConvert.SerializeObject(dt);
            // this is what you're looking for right??
            List<YourEntityType> list = 
    Newtonsoft.Json.JsonConvert
    .DeserializeObject<List<YourEntityType>>(json);
    
    0 讨论(0)
提交回复
热议问题