2009-06-03 7 views
0

Ich habe eine generische Methode eine gespeicherte Prozedur in ASP.NET zu nennen:Anbindung an SQL endet nicht nach einem Aufruf von DB in 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; 
     } 

Auch wenn ich CommandBehavior.CloseConnection nenne die Verbindung nicht geschlossen. Ich kann die Daten in Ordnung bringen, wenn ich zum ersten Mal eine Seite anfordere. Beim Nachladen erhalte ich den folgenden Fehler:

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();

Schließlich, wenn ich sql.Connection.Close() setzen; vor sql.Dispose(); Ich bekomme einen Fehler, dass iReader nicht lesbar ist, weil es bereits geschlossen wurde.

Offensichtlich schließe ich meine Verbindung falsch, kann mir jemand in die richtige Richtung zeigen?

Antwort

4

Wenn Sie einen Datareader zurückkehren, muss die zugrunde liegende Verbindung offen bleiben. Es liegt in der Verantwortung des Verbrauchers, die Ressourcen ordnungsgemäß zu bereinigen.

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

Ich stimme Ihrem Ansatz "die Verantwortung des Verbrauchers, um Ressourcen richtig aufzuräumen." Zu, aber es ist im Allgemeinen nicht darauf zu verlassen, der Verbraucher ist zu faul, um dies zu tun. –

+0

Danke, das hat geholfen. Ich habe eine iReader.Close() nach meiner while-Schleife zu meiner konsumierenden Methode hinzugefügt. – RedWolves

+0

Sie müssen die Verbindung, die Sie in ExecuteStoredProc erstellen, nicht schließen und entsorgen? –

1

Ich würde vorschlagen, die SQL-Verbindung mit einer "using" -Anweisung umschließen, und das wird sich um die meisten SQL-Verbindung Problem kümmern.

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

}

+0

Auch werde ich nicht vorschlagen, SqlDataReader zurücksenden, ist es am besten, Ihr benutzerdefiniertes Objekt zu initialisieren, und dann Ihr Objekt zurückgeben. –

0

Die Idee ist, eine Connection.Close(); Nachdem Sie mit dem SqlReader fertig sind, sollten Sie die Anweisung close() vor dem Befehl SqlReader.Dispose() platzieren, anstatt sie zu platzieren.

0

Dies ist meine bevorzugte Art, IDataReader zu verarbeiten. Lassen Sie den Aufrufer SqlConnection-Instanz erstellen und an Methoden übergeben.

Es ist teuer, eine SqlConnection-Instanz zu erstellen. Und Sie werden am Ende Code aufrufen dieselbe ExecuteStoredProc-Methode mehrmals in verschiedenen Situationen.

Daher refactor ich ExecuteStoredProc-Methode durch Hinzufügen SqlConnection-Instanz als Teil des Parameters.

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

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