使用IDataReader正确读取值

时间:2015-10-12 13:51:51

标签: c# .net sqldatareader datareader

我使用datareader使用sqlcommand从sqltable中检索一些值。现在,当我第一次执行读取器选择值并将它们分配给RemovedRows变量时,它完美地工作。但是当它下次执行填充AddedRows变量时,它什么都不返回。现在,如果我交换变量头寸,AddedRows将有值,后者不会有任何东西。因此,读者基本上执行一次,下一次它不会执行,也不会给读者关闭等任何错误。

using (IDataReader reader = _changeTable.ExecuteReader())
{
   RemovedRows = reader.Select(r => new { LogID = r["LogID"], Operation = r["SYS_CHANGE_OPERATION"] })
                       .Where(r => r.Operation.Equals("D")).Select(r => (long)r.LogID).ToList();

   AddedRows = reader.Select(r => new { LogID = r["LogID"], Operation = r["SYS_CHANGE_OPERATION"] })
                     .Where(r => r.Operation.Equals("I")).Select(r => (long)r.LogID).ToList();
}

public static IEnumerable<T> Select<T>(this IDataReader reader,
                                           Func<IDataReader, T> projection)
{
    while (reader.Read())
    {
        yield return projection(reader);
    }
}

一种解决方案是在new List<T>中拥有阅读器的值并访问新的列表值而不必担心阅读器状态。我能够创建一个List,但由于属性是匿名类型,我无法访问它。

我创建new List<T>并使用它:

    public static List<T> CreateList<T>(params T[] elements)
    {
       return new List<T>(elements);
    }


 var values = reader.Select(r => new { LogID = r["LogID"], Operation = r["SYS_CHANGE_OPERATION"] }).ToList();
 var newList = Helper.CreateList(values);

 RemovedRows = newList.Where(r => r.Operation.Equals("D")).Select(r => (long)r.LogID).ToList();

这里它不允许我访问匿名类型的Operation和LogID属性。

所以我的问题是如何在关闭阅读器之后执行阅读器(下面的代码)并使用它的值:

var values = reader.Select(r => new { LogID = r["LogID"], Operation = r["SYS_CHANGE_OPERATION"] }).ToList();

1 个答案:

答案 0 :(得分:2)

读者已经被枚举,并且只允许一次性向前访问,因此尝试再次枚举它以获得AddedRows结果为空集合。我建议将所有相关行读入内存,然后过滤到单独的查询中:

string[] ops = {"D","I"};

IEnumerable<long> removedRows;
IEnumerable<long> addedRows;

using (IDataReader reader = _changeTable.ExecuteReader())
{
    var allRows = reader.Select(r => new { LogID = r["LogID"], Operation = r["SYS_CHANGE_OPERATION"] })
                        .Where(r => ops.Contains(r.Operation)
                        .ToList();

    removedRows = allRows.Where(r => r.Operation.Equals("D"))
                         .Select(r => (long)r.LogID);

    addedRows = allRows.Where(r => r.Operation.Equals("I"))
                       .Select(r => (long)r.LogID);
}

您还可以使用GroupByToLookup来获得类似的结果,但除非您遇到严重的性能问题,否则请使用对您最有意义的内容。