2010-04-23 6 views
8

Ich habe einen Business Layer, die einen Conn-String und einen SQLCommand zu einer Data Layer geht wie soIst es OK, SQLCommand als Parameter zu übergeben?

public void PopulateLocalData() 
    { 
     System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(); 
     cmd.CommandType = System.Data.CommandType.StoredProcedure; 
     cmd.CommandText = "usp_PopulateServiceSurveyLocal"; 
     DataLayer.DataProvider.ExecSQL(ConnString, cmd); 
    } 

data führt dann nur die SQL-wie so

 public static int ExecSQL(string sqlConnString, System.Data.SqlClient.SqlCommand cmd) 
    { 
     int rowsAffected; 
     using (SqlConnection conn = new SqlConnection(sqlConnString)) 
     { 
      conn.Open(); 
      cmd.Connection = conn; 
      rowsAffected = cmd.ExecuteNonQuery(); 
      cmd.Dispose(); 
     } 
     return rowsAffected; 
    } 

Ist es für mich in Ordnung zu Übergeben Sie den SQLCommand als einen Parameter wie diesen, oder gibt es einen besser akzeptierten Weg, dies zu tun. Eines meiner Bedenken ist, wenn beim Ausführen der Abfrage ein Fehler auftritt, wird die cmd.dispose-Zeile niemals ausgeführt. Bedeutet das, dass es weiterhin Speicher verbraucht, der niemals veröffentlicht wird?

Update:

Erics Beratung Nach mehr ich explizit die Geschäfts- und Datenebenen unterteilt, so dass die Methode in der Business-Schicht wie diese

public void PopulateLocalData() 
    { 
     DataLayer Data = new DataLayer(this.ConnString); 
     Data.UpdateLocalData(); 
    } 

und Methode sucht, die in der Datalayer genannt wird, sieht wie folgt aus .

 public void UpdateLocalData() 
    { 
     using (SqlConnection conn = new SqlConnection(this.ConnString)) 
     using(SqlCommand cmd = new SqlCommand()) 
     { 
      cmd.CommandType = System.Data.CommandType.StoredProcedure; 
      cmd.CommandText = "usp_PopulateServiceSurveyLocal"; 
      conn.Open(); 
      cmd.Connection = conn; 
      cmd.ExecuteNonQuery(); 
     } 
    } 

Auf diese Weise ist es sehr klar ist, dass sowohl der SQLCommand und die SQLConnection werden fachgerecht entsorgt werden. Vielen Dank.

Antwort

6

Im Idealfall sollte Ihre Business-Schicht die Implementierungsdetails Ihrer Datenschicht nicht kennen. Ob Sie also die Datenschicht mit SqlCommand Objekten oder mit etwas wie NHibernate implementieren, sollte für die Business-Schicht irrelevant sein. Dies macht es theoretisch leicht, Ihre Datenschicht zu verschieben und durch eine andere zu ersetzen.

Zusammenfassen: die SqlCommand von der Business-Schicht auf die Datenebene übergeben wird in meinen Augen nicht als gute Praxis betrachtet.

In Bezug auf Dispose(): Wenn Sie eine using-Anweisung (wie using(SqlConnection ...)) verwendet wird, die Dispose() Methode wird automatisch am Ende der using-Anweisung aufgerufen. Sie müssen dies nicht manuell tun.

+0

. Es gibt jedoch keine Verwendung (SqlCommand ...), und das Problem ist, dass der Befehl nicht ordnungsgemäß entsorgt werden kann, wenn etwas fehlschlägt. Die Verbindung ist in Ordnung. – cHao

+0

Soweit ich weiß, ist die Verwendung von (SqlCommand cmd = ...) vollkommen gültig. –

-1

Gut für den Anfang, können Sie es ändern:

public static int ExecSQL(string sqlConnString, System.Data.SqlClient.SqlCommand cmd) 
{ 
    int rowsAffected; 
    try 
    { 
     using (SqlConnection conn = new SqlConnection(sqlConnString)) 
     { 
      conn.Open(); 
      cmd.Connection = conn; 
      rowsAffected = cmd.ExecuteNonQuery(); 
     } 
    } finally { 
     cmd.Dispose(); 
    } 
    return rowsAffected; 
} 

Außerdem habe ich mein Geschäft und Daten in der Regel Schichten mehr trennen als Sie. Meine Business-Schicht würde eine Methode "GetLocalSurvey" in der Datenschicht aufrufen, die den ganzen SQL-Unsinn behandeln würde.

0

Warum Sie es nicht auf diese Änderung:

public static int ExecProcedure(string sqlConnString, string procedureName) 
{ 
    using (var cmd = new System.Data.SqlClient.SqlCommand()) 
    { 
     cmd.CommandType = System.Data.CommandType.StoredProcedure; 
     cmd.CommandText = procedureName; 
     int rowsAffected; 
     using (SqlConnection conn = new SqlConnection(sqlConnString)) 
     { 
      conn.Open(); 
      cmd.Connection = conn; 
      return cmd.ExecuteNonQuery(); 
     } 
    } 
} 

Möchten Sie weitere Parameter? Erstellen Sie Überladungen, Refactor. Teilen Sie den meisten Code in gemeinsamer Funktion. Erstellen new System.Data.SqlClient.SqlCommand() überall ist falsche Ansatz.

0

Derjenige, der den Befehl erstellt, sollte für die Entsorgung verantwortlich sein. Der einfachste Weg dafür ist, den Anruf zu cmd.Dispose von ExecSql und stattdessen rufen Sie Ihre Funktion wie folgt zu entfernen:

public void PopulateLocalData() 
{ 
    using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand()) 
    { 
     cmd.CommandType = System.Data.CommandType.StoredProcedure; 
     cmd.CommandText = "usp_PopulateServiceSurveyLocal"; 
     DataLayer.DataProvider.ExecSQL(ConnString, cmd); 
    } 
} 

Eines meiner Anliegen ist, wenn ein Fehler auftritt, wenn die Abfrage der cmd.dispose Linie wird die Ausführung nie ausführen.Bedeutet das, dass es weiterhin Speicher verbraucht, der niemals veröffentlicht wird?

Zufälligerweise muss SqlClient.SqlCommand nicht entsorgt werden. Dies ist jedoch eine Implementierung Detail, dass Sie nicht darauf verlassen sollen - die allgemeine Regel noch ist: Wenn es IDisposable implementiert, es entsorgen (SqlCeClient.SqlCeCommand zum Beispiel tut Bedarf entsorgt werden ...)

Verwandte Themen