2010-04-23 18 views
8

Mam warstwy biznesowej, która przechodzi ciąg Conn i SqlCommand do warstwy danych Podobnie jakCzy można przekazać SQLCommand jako parametr?

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

dataLayer potem po prostu wykonuje sql Podobnie jak

 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; 
    } 

Czy jest dla mnie OK, aby przekazać komendę SQLC jako parametr podobny do tego lub jest tam lepiej zaakceptowany sposób robienia tego. Jedną z moich obaw jest to, że jeśli wystąpi błąd podczas wykonywania zapytania, linia cmd.dispose nigdy nie zostanie wykonana. Czy to oznacza, że ​​będzie nadal zużywał pamięć, która nigdy nie zostanie wydana?

Aktualizacja:

Po porady Erica ja bardziej wyraźnie podzielony biznesie i dane warstwach, dzięki czemu metoda w warstwy biznesowej wygląda to

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

i metody, która jest wywoływana w dataLayer wygląda następująco .

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

W ten sposób jest oczywiste, że zarówno polecenie SQLC, jak i połączenie SQLConnection zostaną prawidłowo usunięte. Dzięki.

Odpowiedz

6

W idealnym przypadku warstwa biznesowa nie powinna być świadoma szczegółów implementacji warstwy danych. Tak więc, niezależnie od tego, czy zaimplementujesz warstwę danych za pomocą obiektów SqlCommand, czy też za pomocą czegoś w rodzaju NHibernate, nie powinno to mieć znaczenia dla warstwy biznesowej. Dzięki temu teoretycznie łatwo jest "przesunąć" warstwę danych i zastąpić ją inną.

Podsumowując: przekazanie SqlCommand z warstwy biznesowej do warstwy danych jest w moich oczach nie uważane za dobrą praktykę.

chodzi Dispose(): jeśli używasz using-oświadczenie (jak using(SqlConnection ...)), metoda Dispose() nazywa się automatycznie na koniec użyciu instrukcji. Nie musisz tego robić ręcznie.

+0

. Nie ma jednak zastosowania (SqlCommand ...), ale problem polega na tym, że polecenie może nie zostać poprawnie usunięte, jeśli coś się nie powiedzie. Połączenie jest w porządku. – cHao

+0

O ile mi wiadomo, używanie (SqlCommand cmd = ...) jest całkowicie poprawne. –

-1

Więc na początek, można go zmienić na:

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; 
} 

Dodatkowo, ja generalnie oddzielić moja sprawa i dane warstw bardziej niż ty. Moja warstwa biznesowa wywoła metodę "GetLocalSurvey" w warstwie danych, która obsłuży wszystkie bzdury SQL.

0

Dlaczego nie można zmienić go na to:

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

Chcesz dodatkowe parametry? Twórz przeciążenia, refaktor. Udostępnij większość kodu we wspólnej funkcji. Stworzenie new System.Data.SqlClient.SqlCommand() wszędzie jest niewłaściwe podejście.

0

Osoba odpowiedzialna za polecenie powinna być odpowiedzialna za jego usunięcie. Najprostszym sposobem na to, aby usunąć wywołanie cmd.Dispose z ExecSql i zamiast nazwać swoją funkcję tak:

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

Jeden z moich obaw jest sytuacja, gdy wystąpi błąd podczas wykonywania zapytania linia cmd.dispose będzie nigdy nie wykonuj.Czy to oznacza, że ​​będzie nadal zużywał pamięć, która nigdy nie zostanie wydana?

Zbiegiem okoliczności, SqlClient.SqlCommand nie musi być usuwany. To jednak jest szczegółów wdrażania, że ​​nie należy liczyć na - ogólna zasada jest jeszcze: jeżeli realizuje IDisposable wyrzucaj go (SqlCeClient.SqlCeCommand np robi trzeba wyrzucać ...)

Powiązane problemy