目前,我正在使用的應用程序使用強類型DataSet
來處理來自數據庫的數據。我們有一個名爲COM_ControlIn
的表,它表示一個「文件」,其他幾個表與控制表有關係。我需要流的那個叫做COM_GenericTransactionItems
。這個表中有一個名爲COMControlIn_UID
的列,如名字所暗示的那樣將其鏈接到控制表。嘗試在IEnumerable中實現分組以便從數據庫流式傳輸
我們有幾種方法從這個表中獲取數據,例如找到給定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
中,它們與),所以一旦你從數據集中刪除它們,它們本質上是無用的。
聽起來就像你最後會遇到鏈接不同的'DataTable'實例,但很難從您在此顯示的代碼中分辨出來。我假設你的'COM_GenericTransactionItemsDS'類包裝了一個'DataTable'?它的Clear方法有什麼作用? – 2015-02-10 15:18:28
你有沒有考慮過使用庫?如果沒有,你是否考慮過查看庫的源代碼...... – Aron 2015-02-10 15:24:20
你究竟是什麼意思?「我需要像Linq這樣的鍵值對中的數據」?您還應該使用參數而不是將值連接到SQL中以避免潛在的SQL注入。另外,爲什麼不只是發出「SELECT字段FROM COM_GenericTransactionItems WHERE COMControlIn_UID = XXXX ORDER BY CaptureDate,UID;」然後使用'SqlDataReader'遍歷行?您可能必須跟蹤之前的「CaptureDate」,才能像以前一樣控制分組。 – 2015-02-10 16:17:26