2009-06-03 75 views
0

我有一個通用的方法來調用存儲過程在ASP.NET:連接到SQL調用後不打烊到DB在ASP.NET

public SqlDataReader ExecuteStoredProc(string sprocName, SqlParameter[] SqlP) 
     { 
      SqlDataReader iReader; 
      SqlCommand sql = new SqlCommand(); 

      sql.CommandText = sprocName; 
      sql.CommandType = CommandType.StoredProcedure; 
      sql.Connection = ConnStr; 
      if (SqlP != null) 
      { 
       foreach (SqlParameter p in SqlP) 
       { 
        sql.Parameters.Add(p); 
       } 

      } 
      sql.Connection.Open(); 
      iReader = sql.ExecuteReader(CommandBehavior.CloseConnection); 
      sql.Dispose(); 

      return iReader; 
     } 

即使我打電話CommandBehavior.CloseConnection的連接不關閉。第一次請求頁面時,我可以獲取數據。重新加載時出現以下錯誤:

The connection was not closed. The connection's current state is open. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: The connection was not closed. The connection's current state is open.

Source Error:

Line 35: Line 36: } Line 37: sql.Connection.Open(); Line 38: iReader = sql.ExecuteReader(CommandBehavior.CloseConnection); Line 39: sql.Dispose();

最後如果我把sql.Connection.Close();在sql.Dispose()之前;我收到一個錯誤,表示iReader不可讀,因爲它已經關閉。

很明顯,我錯誤地關閉了我的連接,有人能指向正確的方向嗎?

回答

4

當您返回一個DataReader,底層的連接必須保持打開狀態。妥善清理資源是消費者的責任。

public SqlDataReader ExecuteStoredProc(string sprocName, SqlParameter[] SqlP) 
{ 
    SqlCommand sql = new SqlCommand(); 

    sql.CommandText = sprocName; 
    sql.CommandType = CommandType.StoredProcedure; 
    sql.Connection = ConnStr; 
    if (SqlP != null) 
    { 
     foreach (SqlParameter p in SqlP) 
     { 
      sql.Parameters.Add(p); 
     } 

    } 
    sql.Connection.Open(); 
    return sql.ExecuteReader(CommandBehavior.CloseConnection);   
} 

public void ConsumingMethod() 
{ 
    using(SqlDataReader reader = ExecuteStoredProc("MyProc", params)) 
    { 
     while(reader.Read()) 
     { 
      //work with your reader 
     } 
    } 
} 
+0

我同意你的方法「消費者有責任妥善清理資源」,但一般不會依賴於此,消費者也懶得去做。 – 2009-06-03 20:16:29

+0

感謝這有助於。在我的while循環之後,我在我的consumemethod中添加了一個iReader.Close()。 – RedWolves 2009-06-03 20:16:59

+0

您是否需要關閉並處理您在ExecuteStoredProc中創建的連接? – 2010-02-18 19:23:32

1

我會建議使用「using」語句來包裝sql連接,並且會處理大多數sql連接問題。

using (var conn = new SqlConnection("...")) 
{ 
    conn.Open(); 
    using (var cmd = conn.CreateCommand()) 
    { 
     cmd.CommandText = "..."; 
     using (var reader = cmd.ExecuteReader()) 
     { 
      while (reader.Read()) 
      { 
       // ... 
      } 
     } 
    } 

}

+0

此外,我不會建議返回SqlDataReader,最好是初始化您的自定義對象,然後返回您的對象。 – 2009-06-03 20:14:22

0

想法是做一個Connection.Close();在完成SqlReader之後,基本上不用在SqlReader.Dispose()命令之前放置close()語句,而應該將它放在下面。

0

這是我的首選處理IDataReader的方式。讓調用者創建SqlConnection實例並傳遞給方法。

創建SqlConnection實例非常昂貴。最後,代碼會在不同情況下多次調用相同的ExecuteStoredProc方法。

因此,我通過添加SqlConnection實例作爲參數的一部分來重構ExecuteStoredProc方法。

using (SqlConnection conn = new SqlConnection()) 
{ 
    conn.ConnectionString = // Connection String; 
    conn.Open(); 

    using (IDataReader reader = foo.ExecuteStoredProc(conn, sprocName, SqlP)) 
    { 
     // Process IDataReader 
    } 
}