目前,我正在使用的应用程序使用强类型DataSet
s 来处理来自数据库的数据。我们有一个称为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
它们相关的位置),所以一旦你从数据集中删除它们,它们基本上就没有用了。