2009-07-12 8 views
2

Ich wurde in einem Projekt zugewiesen, wo die DAL aus einer Basisklasse mit Funktionen zur Rückgabe von IDataReader, einem Object (int, string und ähnlichem) oder einem DataSet besteht. Eine ExecuteNonQuery-Funktion ist ebenfalls vorhanden. Diese DAL greift nur auf USPs (SQL Server) zu und verwendet MS SqlHelper zum Ausführen der Abfragen. Hier sind zwei Beispielfunktionen von der Basis:SqlConnection von einer Basis-DAL-Klasse beim Aufruf von ExecuteReader absetzen

protected IDataReader ExecuteReader(string storedProcedure, params object[] parameterValues) 
    { 
     SqlConnection HConnection = new SqlConnection(myConnString); 
     IDataReader ret = null; 
     try 
     { 
      ret = SqlHelper.ExecuteReader(HConnection, storedProcedure, parameterValues); 
     } 
     catch (Exception ex) 
     { 
      HanldeError(ex, storedProcedure, parameterValues); 
     } 
     return ret; 
    } 

    protected object ExecuteScalar(string storedProcedure, params object[] parameterValues) 
    { 
     using (SqlConnection HConnection = new SqlConnection(myConnString)) 
     { 
      object ret = null; 
      try 
      { 
       ret = SqlHelper.ExecuteScalar(HConnection, storedProcedure, parameterValues); 
      } 
      catch (Exception ex) 
      { 
       HanldeError(ex, storedProcedure, parameterValues); 
      } 
      return ret; 
     } 
    } 

Andere Klassen leiten sich von dieser Basisklasse, aufgabenspezifische DAL-Klassen erstellen, zum Beispiel:

public class Orders : BaseDal { 
    public IDataReader GetOrdersList(int clientId, int agentId) 
    { 
     return ExecuteReader("usp_Orders_GetOrdersList", clientId, agentId); 
    } 
    ... 
} 

Dann gibt es BLL Klassen, die die DAL-Funktionen aufrufen und mit den Daten (ein Order-Objekt zum Beispiel) Objekte füllen auf der Grundlage der Daten aus dem IDataReader Objekt lesen:

public Order[] GetOrdersList(int ClientIDX, int AgentIDX) 
    { 
     List<Order> ret = null; 
     using (IDataReader dr = objDAL.GetOrdersList(ClientIDX, AgentIDX)) 
     { 
      if (dr != null) 
      { 
       ret = new List<Order>(); 
       while (dr.Read()) 
       { 
        ret.Add(xReadOrder(dr, 0)); 
       } 
      } 
     } 
     return ret.ToArray(); 
    } 

Meine Frage ist - wenn man sich den Code anschauen werde genommen Von BaseDal werden Sie bemerken, dass nur ExecuteScalar das SqlConnection-Objekt (die using-Anweisung) tatsächlich beendet - dies ist bei allen meinen Funktionen der Fall. Mit ExecuteReader kann ich das nicht, da ich ein offenes SqlDataReader-Objekt zurückgebe und das Schließen der Verbindung den Leser ungültig macht. Ich habe alle Code bekommen und mit einem IDataReader von der DAL verwenden Sie die using-Anweisung, aber ist das SqlConnection-Objekt auch entsorgt, oder wird es GC'ed zu einem späteren Zeitpunkt, verletzt die Verbindung Pooling, indem es nicht frei früher? Wenn ja, wie kann dies behandelt werden?

Gibt es auch einen besseren Ansatz zum Erstellen einer DAL als die oben beschriebene? Mir geht es weniger um datenspeicherunabhängige DAL, wir brauchen nur eine solide und einfach zu wartende, die viele gleichzeitige Verbindungen von vielen Threads aufnehmen kann.

Vielen Dank im Voraus für jede Hilfe zu diesem Thema.

Antwort

4

SqlDataReader schließt die Verbindung, wenn Sie beim Ausführen des Befehls CommandBehavior.CloseConnection angeben. Es fühlt sich aber trotzdem ein bisschen hässlich an.

stattdessen eine SqlConnectionin die Methode übergeben und verwendet diesen. Dann hat der Anrufer die Kontrolle darüber, wann das erledigt ist. Alternativ nehmen Sie eine Action<SqlDataReader>, um mit dem offenen Leser auszuführen, und die Methode schließen Sie den Leser und die Verbindung, nach dem Ausführen der Aktion. Diese Aktion müsste dann natürlich alles Notwendige tun, um mit dem Leser zu sprechen.

+0

Danke. Obwohl Sie dies als "hässlich" betrachten, scheint die Verwendung von 'CommandBehavior.CloseConnection' meine beste Option zu sein, da dies SqlHelper intern tut, wenn eine Verbindungszeichenfolge (im Gegensatz zu einem' SqlConnection'-Objekt) übergeben wird. Es ist keine Option, 'SqlConnection' in die Methode zu übergeben, da dies der DAL/BLL-Trennung widerspricht, die ich beibehalten möchte. Der "Action " Ansatz, mit dem ich nicht vertraut bin, aber es scheint ein bisschen mühsam zu sein. Nur um sicher zu gehen - können Sie mir einen guten Platz zeigen, um genau zu sehen, was es genau bedeutet? – synhershko

+0

Ähm, nicht leicht (ich bin dabei, etwas zu reparieren) - aber du würdest einen Lambda-Ausdruck verwenden, um zu sagen "wenn du den Leser offen hast, das ist es, was ich damit machen will" . –