【问题标题】:Combining multiple data readers into one将多个数据读取器合二为一
【发布时间】:2017-05-24 01:06:53
【问题描述】:

我有一些代码 (C#/ADO.NET),其中有 2 个或更多读取器(IDataReader 实例) - 每个都可能是多个数据集的读取器,旨在通过 NextResult API。

我的任务是将这些组合成一个阅读器并将其返回给我的调用者,以便他们可以通过这个单个阅读器枚举所有不同的结果 - 必要时调用 NextResult

(请注意,每个数据集都有不同类型的数据。)。

似乎是一个有效的用例。应该有什么方法可以做到这一点?

【问题讨论】:

    标签: c# sql ado.net


    【解决方案1】:

    只是为了好玩,我尝试在下面创建一个类。测试肯定很麻烦。

    在解释为什么会很痛苦之前,我会为您提供一个免去麻烦的借口。如果您的班级正在创建IDataReaders,则可能没有充分的理由将它们传递给调用者。您可以从它们中读取数据并将 that 传递给调用者。调用者需要阅读器而不仅仅是实际数据有什么好的理由吗?打开和关闭数据阅读器是您想要完成的事情,而无需过多参与此过程,因此,如果您可以打开它,获取您需要的内容,然后关闭它,那是理想的。

    当我们在IDataReader 中从一个结果集前进到下一个结果集时,通常是在进行单个调用的上下文中,因此更容易了解结果集是什么。我们刚刚调用了过程 XYZ,它返回两个结果集,所以我们必须检查这两个结果集。我不想处理具有大量结果集的IDataReader,尤其是当它是一堆人为组合的较小结果集时。您必须跟踪大量结果集并在不同的方法之间切换以读取它们,因为它们包含不同的列。

    还有那些开放连接的问题。我们通常在完成阅读器后关闭连接。但现在还不清楚该连接何时关闭。你怎么知道哪个连接属于哪个阅读器?如果您关闭另一个阅读器的连接,而另一个阅读器仍在使用它会怎样?

    所以这里有一个大概的样子。我显然没有测试这个。如果调用NextResult 并且当前阅读器中没有下一个结果,您将必须跟踪哪个是当前阅读器并处理前进到下一个阅读器。而且您必须关闭阅读器并确保它们都被处理掉。这可以进行测试,但只是测试会让人头疼,这通常是一个很好的警告,不要做某事。

    public class AggregateDataReader : IDataReader
    {
        private readonly Queue<IDataReader> _readers;
        private IDataReader _current;
    
        public AggregateDataReader(IEnumerable<IDataReader> readers)
        {
            _readers = new Queue<IDataReader>(readers);
        }
    
        private bool AdvanceToNextReader()
        {
            _current?.Dispose();
            var moreReaders = _readers.Any();
            if (moreReaders) _current = _readers.Dequeue();
            return moreReaders;
        }
    
        public bool NextResult()
        {
            if (_current == null) return false;
            if (_current.NextResult()) return true;
            return AdvanceToNextReader();
        }
    
        public bool Read()
        {
            return _current.Read();
        }
    
        public void Dispose()
        {
            _current?.Dispose();
            while (_readers.Any()) _readers.Dequeue().Dispose();
        }
    
        public string GetName(int i)
        {
            return _current.GetName(i);
        }
    
      ... lots of these...
    
        public byte GetByte(int i)
        {
            return _current.GetByte(i);
        }
    
        public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
        {
            return _currentGetBytes(i, fieldOffset, buffer, bufferoffset, length);
        }
    
       ... etc...
    
        public void Close()
        {
            _current?.Close();
            while (_readers.Any()) _readers.Dequeue().Close();
        }
    
       ... etc...
    }
    

    【讨论】:

    • 谢谢。我了解其中的陷阱并将提防它们。这似乎是一个复杂但有效的用例,应该已经建立了像您这样的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-30
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    • 2019-11-06
    相关资源
    最近更新 更多