2016-09-23 59 views
5

我想使用Task.WhenAll執行多個SqlDataReaders。但是當任務正在等待時,我得到任務,當所有,連接關閉

「System.InvalidOperationException:操作無效,連接 已關閉」。任務

創作:

 List<Task<SqlDataReader>> _listTasksDataReader = new List<Task<SqlDataReader>>(); 
     _listTasksDataReader.Add(GetSqlDataReader1(10)); 
     _listTasksDataReader.Add(GetSqlDataReader2(10)); 
     SqlDataReader[] _dataReaders = await Task.WhenAll(_listTasksDataReader); 

我 「SqlDataReader對象」 的方法:

public Task<SqlDataReader> GetSqlDataReader1(int recordCount) 
    { 
     using (var sqlCon = new SqlConnection(ConnectionString)) 
     { 
      sqlCon.Open(); 
      using (var command = new SqlCommand("sp_GetData", sqlCon)) 
      { 
       command.Parameters.Clear(); 
       command.Parameters.Add(new SqlParameter("@recordCount", recordCount)); 
       command.CommandType = System.Data.CommandType.StoredProcedure; 
       return command.ExecuteReaderAsync(); 
      } 
     } 
    } 

不應該執行Task.WhenAll當數據庫連接打開還是我失去了一些東西?

+0

你有兩個連接。你在哪個連接上發生錯誤? 我會在sqlCon上設置一個斷點。打開()並查看您的代碼是否正在運行[兩次],並且連接實際上正在打開。 –

+4

只要您的'ExecuteReaderAsync'調用返回,您的連接就會關閉(因爲它在'using'語句中聲明)。您的'ExecuteReaderAsync'調用在*數據讀取之前返回*(畢竟它是一個異步讀取器!)。 –

+2

由於返回語句而退出使用塊,因此連接關閉。你應該看看http://codereview.stackexchange.com/a/22916/54013 – AntonR

回答

2

更新:我要離開這裏了這一點,但我只是記得,你不許結合yieldawait ......至少現在還沒有。


記住,調用command.ExecuteReaderAsync(),甚至與return關鍵字,不停止方法的執行。這就是_Async()方法的全部要點。所以緊接着該函數調用之後,代碼將退出using塊。這有可能在您有機會使用它讀取DataReader之前丟棄連接對象。

嘗試返回一個Task<IEnumerable<IDataRecord>>代替:

public async Task<IEnumerable<IDataRecord>> GetSqlDataReader1(int recordCount) 
{ 
    using (var sqlCon = new SqlConnection(ConnectionString)) 
    using (var command = new SqlCommand("sp_GetData", sqlCon)) 
    { 
     command.Parameters.Add("@recordCount", SqlDbType.Int).Value = recordCount; 
     command.CommandType = System.Data.CommandType.StoredProcedure; 

     sqlCon.Open();    
     var rdr = await command.ExecuteReaderAsync(); 
     while (rdr.Read()) 
     { 
      yield return rdr; 
     } 
    } 
} 

注意,有一個 「疑難雜症」 這種模式。每個yield return使用相同的對象,因此如果你不小心,可能會發生一些奇怪的事情。我建議進一步改變這包括代碼,把數據從每個記錄在rdr對象到它自己的(強類型)對象實例:

public async Task<IEnumerable<SomeObject>> GetSqlDataReader1(int recordCount) 
{ 
    using (var sqlCon = new SqlConnection(ConnectionString)) 
    using (var command = new SqlCommand("sp_GetData", sqlCon)) 
    { 
     command.Parameters.Add(new SqlParameter("@recordCount", recordCount)); 
     command.CommandType = System.Data.CommandType.StoredProcedure; 

     sqlCon.Open();     
     var rdr = await command.ExecuteReaderAsync(); 
     while (rdr.Read()) 
     { 
      yield return new SomeObject() {Field1 = rdr[1], Field2 = rdr[2], etc}; 
     } 
    } 
} 
+0

現在已經重寫了從閱讀器收集數據的方法,而是返回任務。 – AsusT9

5

這是可能的CommandBehavior.CloseConnection傳遞給ExecuteReaderAsync。然後連接將保持打開狀態,直到返回的數據讀取器對象關閉爲止:請參閱MSDN herehere。在這種情況下,SqlConnection不需要在using語句中。

像這樣:

public Task<SqlDataReader> GetSqlDataReader1(int recordCount) 
{ 
    var sqlCon = new SqlConnection(ConnectionString); 
    sqlCon.Open(); 

    using (var command = new SqlCommand("sp_GetData", sqlCon)) 
    { 
     command.Parameters.Clear(); 
     command.Parameters.Add(new SqlParameter("@recordCount", recordCount)); 
     command.CommandType = System.Data.CommandType.StoredProcedure; 
     return command.ExecuteReaderAsync(CommandBehavior.CloseConnection); 
    } 
} 
2

我這麼想嗎?

您試圖獲得SqlDataReader沒有底層連接?我認爲這不會奏效。從讀者那裏讀到什麼會發生什麼?連接已關閉。

所以,你可能只需要關閉連接之前讀取實際數據:

public async Task<List<T>> GetData1(int recordCount) 
{ 
    using (var sqlCon = new SqlConnection(ConnectionString)) 
    { 
     sqlCon.Open(); 
     using (var command = new SqlCommand("sp_GetData", sqlCon)) 
     { 
      command.Parameters.Clear(); 
      command.Parameters.Add(new SqlParameter("@recordCount", recordCount)); 
      command.CommandType = System.Data.CommandType.StoredProcedure; 

      var result = new List<T>(); 
      var reader = await command.ExecuteReaderAsync(); 
      // TODO: use `reader` to populate `result` 
      return result; 
     } 
    } 
} 
+0

感謝您的回覆。我現在明白爲什麼會出現這個錯誤並且已經調整了數據讀取器方法。 – AsusT9