如何在C#中将IDataReader转换为Stream

4

在我的WCF服务中,我正在使用Command.ExecuteReader()方法从SQL服务器检索数据。 数据大小非常大(约为1 GB),并且通过netTcp绑定将此数据传输到客户端。

我计划在WCF中实现流模式而不是缓冲模式。 有人可以指向任何文章或文档来完成相同的操作吗?

简单来说,我的目标是将IDataReader转换为流对象,该对象将传输到客户端,客户端希望将该流转换回数据集/数据表或可以与网格绑定的任何内容。

由于数据通过SP传递,并且输出集中的列数保持变化(我不想在代码中添加列数限制),因此无法将IDataReader转换为IEnumerable。

最终通信将从WCF服务到客户端应用程序进行数据集。 如果有任何解决方案,例如将数据集转换为流,将其发送到客户端,然后在客户端将流转换回数据集,也可以解决我的问题。


为什么不将数据读入类并返回该类?DataReader的目的是从数据库层传输数据,而不是用作服务契约。 - Ricardo Pontual
请查看更新的问题。 - Abhash786
Datareader 与数据库连接,它将逐一读取数据,由于需要循环读取以获取所有数据,所以无法通过 WCF 服务使用 Datareader。当您这样做时,必须将返回的数据传递给某个对象,通常是一个类,并且应该返回此类或此类的流。 - Ricardo Pontual
2个回答

1
你可以像这样将任何内容转换为流:

you can convert anything to stream like this:

var stream = new MemoryStream(Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(datareader)));

但这不是最佳实践。你应该使用数据读取器创建一个对象数组,然后返回它。


一个 Datareader 对象必须被“循环”以获取数据,我认为它不能像这个例子一样被流式传输。 - Ricardo Pontual

1
你不应该尝试将IDataReader转换为流,而是让你的数据访问方法返回一个IEnumerable类型,该类型表示查询结果的单行,如下所示:
public IEnumerable<Order> GetOrders()
{
   IDbCommand cmd = ...  <<build your command here>> ...
   using(var rdr = cmd.ExecuteDataReader())
   {
      while(rdr.Read())
      {
          Order order = new Order {Id=rdr.GetDecimal(1), Name=rdr.GetString(2)};
          yield return order;
      }
   }
}

接下来,您可以将此方法的结果序列化到流中(例如@Mohamed所示)。这样,您可以向客户端发送对象列表,而无需将完整的结果集加载到内存中。并且当阅读器达到结果的末尾时,您仍然可以确保数据阅读器已被处理。

我认为这个想法是正确的,正如@Marc-Selis所指出的那样。再次强调,在循环之前不能使用Datareader进行流式处理或其他任何操作以获取所有数据。 - Ricardo Pontual
你试图做的事情:创建一个能够查询数据库中任何内容的单一方法被认为是非常糟糕的设计。WCF是一个依赖于契约的通信框架。而这个契约应该被视为相当字面意义上的:客户端和服务器之间关于将要在请求和响应中发送什么数据的协议。在你的问题中,服务器可以返回任何它想要的东西。换句话说,WCF不是一个很好的技术选择。 - Marc Selis
如果你真的想让它工作,你可能会成功,但是你必须使用DbCommand.ExecuteDataSet而不是ExecuteDataReader,并使用@Mohammed提供的方法将数据集序列化到流中。 - Marc Selis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接