尝试在IEnumerable中实现分组以从数据库流

时间:2015-02-10 14:04:40

标签: c# sql-server linq batching

目前我正在使用的应用程序使用强类型DataSet来处理来自数据库的数据。我们有一个名为COM_ControlIn的表,代表一个"文件"和其他几个表与控制表有关系。我需要流式传输的是COM_GenericTransactionItems。这个表中有一个名为COMControlIn_UID的列,它根据名称将其链接到控制表。

我们有几种方法可以从这个表中获取数据,例如查找给定COMControlIn_UID的所有记录的方法,但所有这些的问题是它们一次获取所有记录,这将成为一个现在问题是,大量的数据导致我们达到.NET的内存限制。我们所有的现有代码都使用由Visual Studio从数据库模式生成的XSD构建的强类型数据集。

我的想法是使用IEnumerable来"流"来自数据库的批量记录,而不是一次性获取所有内容,同时仍保留我们之前使用的强类型数据集,以保持其兼容而不进行重大更改。我写的代码或多或少看起来像这样:

COM_GenericTransactionItemsDS com_GenericTransactionItemsDS = new COM_GenericTransactionItemsDS();
long lastUID = 0;
using (SqlConnection sqlConnection = new SqlConnection("...")
{
  sqlConnection.Open();
  SqlCommand sqlCommand = new SqlCommand("SELECT MAX(UID) FROM COM_GenericTransactionItems WHERE COMControlIn_UID = " + p_COMControlIn_UID, sqlConnection);
  //because apparently I'm not allowed to straight cast...
  long maxUID = Convert.ToInt64(sqlCommand.ExecuteScalar());
  while (lastUID < maxUID)
  {
    com_GenericTransactionItemsDS.Clear();
    using (SqlDataAdapter sqlDataAdapter = new SqlDataAdapter())
    {
      //Build Select
      string strSQL = "SELECT TOP(" + fetchAmount + ") " + SQL_Columns + " FROM COM_GenericTransactionItems " +
                      "WHERE COMControlIn_UID = " + p_COMControlIn_UID.ToString() + " AND UID > " + lastUID + " ORDER BY UID";
      //Get Data
      sqlDataAdapter.SelectCommand = new SqlCommand(strSQL, sqlConnection);
      sqlDataAdapter.SelectCommand.CommandTimeout = Convert.ToInt32(context.strContext[(int)eCCE_Context._COMMAND_TIMEOUT]);
      sqlDataAdapter.Fill(com_GenericTransactionItemsDS, "COM_GenericTransactionItems");
      lastUID = com_GenericTransactionItemsDS.COM_GenericTransactionItems.Max(r => r.UID);
    }
    yield return com_GenericTransactionItemsDS;
  }
}

它非常适合获取数据并且显着降低了我们的内存使用量,但是我遇到了一个问题。

我需要通过特定列(日期)对此表中的项目进行分组,但这一概念与整个批处理方法冲突,因为您需要知道整个数据集的外观是什么样的。

我无法在SQL中进行分组,因为在切换到使用此方法之前,我需要像Linq这样的键值对中的数据(除非有办法让我这样做)这在SQL中。)

当我尝试使用SelectMany将所有行展平为一个可枚举时,每当我尝试访问其中任何行时,我都会RowNotInTableException。我真的不知道还有什么可以尝试。

作为参考,这是我用来进行分组的Linq查询:

var dateGroups = from row in p_COM_GenericTransactionItemsDS.SelectMany(c => c.COM_GenericTransactionItems) group row by (DateTime)row[tableDefinitions.CaptureDate] into groups select groups;

我认为问题在于我从流媒体方法返回数据的方式,但我不知道如何做到这一点。理想情况下,我希望将数据表中的所有行提取到IEnumerable中,然后重复执行,但DataRows不要保留表格的模式(我已经读过架构保存在与它们相关的DataTable中,所以一旦从数据集中删除它们,它们就基本没用了。

1 个答案:

答案 0 :(得分:0)

我解决了我的问题。我改变了我的流式方法来循环遍历它在批处理中接收的项目,复制它们并逐个返回它们,如下所示:

foreach (COM_GenericTransactionItemsDS.COM_GenericTransactionItemsRow row in com_GenericTransactionItemsDS.COM_GenericTransactionItems.Rows)
{
  lastUID = row.UID;
  COM_GenericTransactionItemsDS.COM_GenericTransactionItemsRow newRow = com_GenericTransactionItemsDS.COM_GenericTransactionItems.NewCOM_GenericTransactionItemsRow();
  newRow.ItemArray = row.ItemArray;
  yield return newRow;
}