2015-02-10 15 views
0

目前,我正在使用的應用程序使用強類型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中,它們與),所以一旦你從數據集中刪除它們,它們本質上是無用的。

+0

聽起來就像你最後會遇到鏈接不同的'DataTable'實例,但很難從您在此顯示的代碼中分辨出來。我假設你的'COM_GenericTransactionItemsDS'類包裝了一個'DataTable'?它的Clear方法有什麼作用? – 2015-02-10 15:18:28

+0

你有沒有考慮過使用庫?如果沒有,你是否考慮過查看庫的源代碼...... – Aron 2015-02-10 15:24:20

+0

你究竟是什麼意思?「我需要像Linq這樣的鍵值對中的數據」?您還應該使用參數而不是將值連接到SQL中以避免潛在的SQL注入。另外,爲什麼不只是發出「SELECT字段FROM COM_GenericTransactionItems WHERE COMControlIn_UID = XXXX ORDER BY CaptureDate,UID;」然後使用'SqlDataReader'遍歷行?您可能必須跟蹤之前的「CaptureDate」,才能像以前一樣控制分組。 – 2015-02-10 16:17:26

回答

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; 
} 
相關問題