自定义通用IEnumerator绑定到数据库

时间:2012-08-08 15:38:36

标签: c# sql generics ienumerable

我所做的工作涉及从SQL服务器数据库将大量数据下载到内存中。为了实现这一点,我们使用SqlDataReader加载自定义数据集定义,然后遍历Datatable并将每一行构建到一个对象中,然后通常将这些对象打包成一个庞大的字典。

我们使用的数据量足够大,有时它无法容纳到具有内存上限的单个数据表中。在最极端的情况下,字典甚至已经增长到足以超过8 gb的系统内存。当数据表溢出时,我正在完成修复outofmemory异常的任务。我通过实现一个似乎与数据表的使用方式相冲突的批处理方法来做到这一点,但它暂时起作用。

我现在的任务是进一步降低此过程的内存要求。我的想法是创建一个继承自IEnumerator 的通用类型的类,它接受一个SqlDataReader并且基本上使用reader作为Enumerating的集合。 MoveNext()函数将推进阅读器,Current属性将从阅读器的当前行返回从构建器方法指定的指定类型对象。

我的问题:这是一个可行的想法吗?我从来没有听过/无法在网上找到类似的东西。

另外,从逻辑上讲:当调用Current属性时,如何调用类型声明所需的特定构建器函数?

我愿意批评和惩罚梦想一个愚蠢的想法。我最感兴趣的是找到实现总体目标的最佳实践。

1 个答案:

答案 0 :(得分:3)

似乎合情合理,实际上使用迭代器块非常简单:

private static IEnumerable<Foo> WrapReader(SqlDataReader reader)
{
    while (reader.Read())
    {
        Foo foo = ...; // TODO: Build a Foo from the reader
        yield return foo;
    }
}

然后你可以用它:

using (SqlDataReader reader = ...)
{
    foreach (Foo foo in WrapReader(reader))
    {
        ...
    }
}

如果你小心,你甚至可以使用LINQ to Objects:

using (SqlDataReader reader = ...)
{
    var query = from foo in WrapReader(reader)
                where foo.Price > 100
                select foo.Name;
    // Use the query...
}