【问题标题】:How to use Generic with SqlDataReader如何将泛型与 SqlDataReader 一起使用
【发布时间】:2018-09-01 22:47:50
【问题描述】:

我试图想出一种方法,只需将表从 SQL Server 加载到类中,而无需告诉它任何内容。基本上,只需创建类并让它知道要加载什么,基于此。这是我目前所拥有的。

我的问题是,有什么方法可以避免对类型进行硬编码,调用 reader.readString, reader.readString。 readInt32等..基于FieldType?

 private Int32? readInt32(SqlDataReader reader, string columnName)
    {
        Int32? result = null;


        if (!reader.IsDBNull(reader.GetOrdinal(columnName)))
        {
            result = reader.GetInt32(reader.GetOrdinal(columnName));
        };

        return result;
    }

  public List<T> readTable(string table, string wherecls, string connStr)
    {
        List<T> result = new List<T>();
        using (SqlConnection connection = new SqlConnection(connStr))
        {
            using (SqlCommand command = connection.CreateCommand())
            {
                command.CommandText = "select * from " + table;
                if (wherecls.Length > 0) command.CommandText += " where " + wherecls;
                connection.Open();
                using (var reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        Object i = Activator.CreateInstance(typeof(T));

                        System.Reflection.FieldInfo[] fieldInfoList = typeof(T).GetFields();
                        foreach (System.Reflection.FieldInfo f in fieldInfoList)
                        {
                            if (f.FieldType == typeof(string)) f.SetValue(i, readString(reader, f.Name));
                            if (f.FieldType == typeof(Int32)) f.SetValue(i, readInt32(reader, f.Name));
                            if (f.FieldType == typeof(Int16)) f.SetValue(i, readInt16(reader, f.Name));
                            if (f.FieldType == typeof(byte)) f.SetValue(i, readByte(reader, f.Name));
                            if (f.FieldType == typeof(short)) f.SetValue(i, readShort(reader, f.Name));
                        }
                        result.Add((T)i);
                    }
                }
            }
        }
        return result;
    }

谢谢你, 丹·蔡斯

【问题讨论】:

标签: c# .net reflection ado.net sqlclient


【解决方案1】:

您所描述的工作量很大......而且正是像“dapper”这样的工具已经在做。所以我的建议是:使用 dapper

// Dapper adds a Query<T>(this DbConnection, ...) extension method
var data = connection.Query<T>(sql, args).AsList();

但是,我string wherecls 让我脊背发凉——这听起来像是 SQL 注入的噩梦。但是……这取决于你。

【讨论】:

  • 我很欣赏这个建议,但如果我可以使 readInt32 泛型为 readValue,那么我什至用 2 个函数替换了 dapper..?我真的只想要一个功能。
  • @DanChase 让您刚刚获得的建议真正融入其中。
  • @DanChase 我不能扭动你的手臂......只是:这里没有魔杖可以让它不是很多工作:)
  • 我肯定会去看看 Dapper,只是在尝试这个,还学到了很多关于反射和泛型的尝试。
  • 哇.. 只是.. 哇。安装的 Dapper 在 5 分钟内消除了我 90% 的代码,并且它立即运行而没有问题。!!!
【解决方案2】:

试试这个。

确保该类型有一个公共默认构造函数——一个不带参数的构造函数——并且 SQL 字符串中的列名与该类型的公共属性的名称完全匹配。

namespace MyNamespace {
    using System;
    using System.Collections.Generic;
    using System.Data.SqlClient;
    using System.Reflection;

    public static class MyExtensions {

        public static IEnumerable<T> Query<T>(this SqlConnection cn, string sql) {
            Type TypeT = typeof(T);
            ConstructorInfo ctor = TypeT.GetConstructor(Type.EmptyTypes);
            if (ctor == null) {
                throw new InvalidOperationException($"Type {TypeT.Name} does not have a default constructor.");
            }
            using (SqlCommand cmd = new SqlCommand(sql, cn)) {
                using (SqlDataReader reader = cmd.ExecuteReader()) {
                    while (reader.Read()) {
                        T newInst = (T)ctor.Invoke(null);
                        for (int i = 0; i < reader.FieldCount; i++) {
                            string propName = reader.GetName(i);
                            PropertyInfo propInfo = TypeT.GetProperty(propName);
                            if (propInfo != null) {
                                object value = reader.GetValue(i);
                                if (value == DBNull.Value) {
                                    propInfo.SetValue(newInst, null);
                                } else {
                                    propInfo.SetValue(newInst, value);
                                }
                            }
                        }
                        yield return newInst;
                    }
                }
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-02
    • 2011-02-09
    • 2019-03-21
    • 2017-01-11
    • 2016-04-07
    • 1970-01-01
    相关资源
    最近更新 更多