使用一个函数从DataRow或DataReader中提取

时间:2011-06-09 13:58:50

标签: c# .net sql datareader datarow

我正在寻找一种解决方案,以便在使用DataRow和只有一个函数(或一个基本函数)的DataReader时如何从数据库中提取数据。

我的问题源于这样一个事实:有时候我需要一个DataReader,有时我需要一个DataTable / DataRow但是为了从这些对象中提取数据,我需要两个单独的数据访问方法,因为它们不共享一个接口。 / p>

基本上,当我的数据库结构发生变化时,我不想进入多个函数中编写以下数据检索代码:

someValue = dr["someValue"]

它的语法相同,并且做同样的事情所以我想要一个共享该功能的函数,无论我是使用DataReader还是DataTable / DataRow从数据库中提取数据。

5 个答案:

答案 0 :(得分:5)

您可以在DataTable类中使用CreateDataReader方法通过DbDataReader基类访问数据。因此,您可以更改实现,但保留映射。

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

如果您可以移动到无需手动映射的ORM,那会更好。

看看这个微观ORM Dapper

答案 1 :(得分:2)

使用this文章将datareader转换为数据表,然后您可以将它们作为数据表接口

所以你基本上会添加这个从dataLayer调用的函数:

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);
  }
}

然后在你得到数据表的函数中,如果它是一个dataReader你会做一个,将读者传递给函数返回一个数据表:

DataTable dtFromReader = ConvertDataReader(dr);

答案 2 :(得分:1)

你的意思是自动映射sql查询结果的行到一个实体?喜欢这个?

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;
}

答案 3 :(得分:0)

创建适配器以隐藏DataReader的实施,以使用DataTable/DataRow代码

答案 4 :(得分:0)

作为替代解决方案,我使用了一个带有动态参数的私有函数。 然后添加了两个带有“DataRow”和“DataReader”参数的公共函数。 您可以使用它来限制对已知类型或接口的调用。

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;
}

尽管有警告。您可能需要稍微重写您的加载代码,因为动态上通过字符串访问的dr内容的行为略有不同。即

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

可能需要更改为

if(dr["someValue"] is DBNull)

但是这种方法仍然避免了重复的加载代码问题。