代码之家  ›  专栏  ›  技术社区  ›  Jared275

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

  •  2
  • Jared275  · 技术社区  · 12 年前

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

    我们使用的数据量足够大,有时它无法容纳在一个有内存上限的数据表中。字典甚至变得足够大,在最极端的情况下可以超过8gb的系统内存。我的任务是修复数据表溢出时抛出的内存外异常。我通过实现一个批处理方法来做到这一点,该方法似乎与数据表的使用方式相冲突,但它暂时有效。

    我现在的任务是进一步减少这个过程的内存需求。我的想法是创建 继承自IEnumerator的泛型类型类 它采用SqlDataReader,并基本上将该读取器用作正在枚举的集合。MoveNext()函数将推进读取器,Current属性将从读取器的当前行返回指定的类型化对象,该对象是通过构建器方法构建的。

    我的问题是:这是一个可行的想法吗?我从未听说过/在网上找不到这样的东西。

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

    我愿意接受批评和指责,因为我想出了一个愚蠢的主意。我最感兴趣的是找到实现总体目标的最佳实践。

    1 回复  |  直到 12 年前
        1
  •  3
  •   Jon Skeet    12 年前

    使用迭代器块看起来相当合理,实际上也相当简单:

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