尝试在 IEnumerable 中实现分组以从数据库流式传输
Trying to implement grouping in IEnumerable to stream from Database
目前,我正在使用的应用程序使用强类型 DataSet
s 来处理数据库中的数据。我们有一个叫做COM_ControlIn
的table代表一个"file"和其他几个table与控件table有关系。我需要从中流式传输的那个叫做 COM_GenericTransactionItems
。 table 中有一列名为 COMControlIn_UID
,顾名思义,它将它链接到控件 table。
我们有几种方法可以从此 table 中获取数据,例如找到给定 COMControlIn_UID
的所有记录的方法,但所有这些方法的问题是它们获取所有记录一次,现在这已成为一个问题,因为庞大的数据量导致我们达到 .NET 的内存限制。我们现有的所有代码都使用由 Visual Studio 从数据库模式生成的 XSD 构建的强类型数据集。
我的想法是使用 IEnumerable
到 "stream" 批数据库中的记录,而不是一次获取所有内容,同时仍然保留我们之前使用的强类型数据集以保持其兼容性没有重大变化。我写的代码大致是这样的:
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;
}
}
它在获取数据方面非常有效,并且显着降低了我们的内存使用量,但我 运行 遇到了一个问题。
我需要按特定列(日期)将此 table 中的项目分组,但这种概念与整个批处理方法冲突,因为您需要知道整个数据集的外观进行分组。
我无法在 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;
我认为问题出在我从流式传输方法返回数据的方式上,但我不知道还能怎么做。理想情况下,我想将我们数据 table 中的所有行提取到 IEnumerable
中并迭代它,但是 DataRows
不要保留 table' s 模式(我读过该模式保存在它们相关的 DataTable
中),所以一旦你从数据集中删除它们,它们基本上就没用了。
我的问题已经解决了。我更改了我的流媒体方法以循环遍历它批量接收的项目,制作它们的副本并 return 一个一个地 return 它们,如下所示:
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;
}
目前,我正在使用的应用程序使用强类型 DataSet
s 来处理数据库中的数据。我们有一个叫做COM_ControlIn
的table代表一个"file"和其他几个table与控件table有关系。我需要从中流式传输的那个叫做 COM_GenericTransactionItems
。 table 中有一列名为 COMControlIn_UID
,顾名思义,它将它链接到控件 table。
我们有几种方法可以从此 table 中获取数据,例如找到给定 COMControlIn_UID
的所有记录的方法,但所有这些方法的问题是它们获取所有记录一次,现在这已成为一个问题,因为庞大的数据量导致我们达到 .NET 的内存限制。我们现有的所有代码都使用由 Visual Studio 从数据库模式生成的 XSD 构建的强类型数据集。
我的想法是使用 IEnumerable
到 "stream" 批数据库中的记录,而不是一次获取所有内容,同时仍然保留我们之前使用的强类型数据集以保持其兼容性没有重大变化。我写的代码大致是这样的:
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;
}
}
它在获取数据方面非常有效,并且显着降低了我们的内存使用量,但我 运行 遇到了一个问题。
我需要按特定列(日期)将此 table 中的项目分组,但这种概念与整个批处理方法冲突,因为您需要知道整个数据集的外观进行分组。
我无法在 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;
我认为问题出在我从流式传输方法返回数据的方式上,但我不知道还能怎么做。理想情况下,我想将我们数据 table 中的所有行提取到 IEnumerable
中并迭代它,但是 DataRows
不要保留 table' s 模式(我读过该模式保存在它们相关的 DataTable
中),所以一旦你从数据集中删除它们,它们基本上就没用了。
我的问题已经解决了。我更改了我的流媒体方法以循环遍历它批量接收的项目,制作它们的副本并 return 一个一个地 return 它们,如下所示:
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;
}