2008-10-30 7 views
21

Wurde gefragt, ob es empfohlen wird, ein Datenbankverbindungsobjekt (zu anderen Modulen) zu übergeben oder die Methode (im anderen Modul) für die Einrichtung zuständig zu machen. Ich lehne es an, die Methode so einzurichten, dass der Zustand der Verbindung nicht überprüft werden muss, bevor sie verwendet wird, und dass der Anrufer alle erforderlichen Daten an die aufrufende Methode weitergibt, die zum Einrichten der Verbindung benötigt wird.DB-Verbindungsobjekt an Methoden übergeben

Antwort

13

Persönlich mag ich fest verwenden beschränkte Verbindungen; öffne sie spät, benutze sie und schließe sie (in einem "using" -Block, alles innerhalb der lokalen Methode). Beim Verbindungs-Pooling wird in den meisten Fällen die Verbindung wieder verwendet, sodass bei diesem Ansatz kein echter Overhead entsteht.

Der Hauptvorteil nebenbei Verbindungen verwendet so zu sein, dass Sie die Transaktion um passieren könnte; TransactionScope ist jedoch eine einfachere Möglichkeit, eine Transaktion zwischen Methoden zu teilen.

Da die Klassen implementierungsspezifisch sind, schreibe ich jedes, um seine eigene native Transaktion zu öffnen. Andernfalls können Sie die ado.net-Factory-Methoden verwenden, um den entsprechenden Typ aus der Konfigurationsdatei (dem Provider-Namen) zu erstellen.

+4

Wenn Sie Transaction verwenden, um eine Transaktion zwischen Methoden zu teilen, die unterschiedlichen Verbindungen verwenden, wird die Transaktion eine verteilte Transaktion mit der damit verbundene Overhead. Es ist also oft besser, eine Verbindung (und ihre Transaktion) zwischen Methoden zu übergeben, während der Umfang eng bleibt. – Joe

+0

Das ist ein weiterer Grund, warum ich TLS für dieses Zeug verwende –

+0

Dies ist die Art, wie wir es normalerweise tun, und die Art, wie ich es bevorzuge. – CSharpAtl

1

ich persönlich arbeiten, um meinen Datenzugriff so viel wie möglich zu zentralisieren, wenn jedoch nicht möglich, dass ich immer eine neue Verbindung in den anderen Klassen öffnen, wie ich finde, dass es zu viele andere Dinge, die in der Quere kommen können, wenn Übergabe des eigentlichen Verbindungsobjekts.

0

würde ich die web.config verwenden

<configuration> 
    <connectionStrings> 
     <add name="conn1" providerName="System.Data.SqlClient" connectionString="string here" /> 
     <add name="conn2" providerName="System.Data.SqlClient" connectionString="string here" /> 
    </connectionStrings> 
</configuration> 

Dann können Sie es von überall in der Anwendung verweisen

+0

Aber ich nicht jedes Stück will, dass haben, um von der Config, hat 1-Klasse, die die Verbindungen – CSharpAtl

+0

mananages Ist es sicher, die Verbindungszeichenfolge in der Konfigurationsdatei ohne Verschlüsselung zu setzen? –

1

Verbindungsaufbau ist möglicherweise teuer und fügt möglicherweise eine Rundreise. Also, wiederum, möglicherweise ist das bessere Design, das Verbindungsobjekt zu übergeben.

Ich sage möglicherweise, weil, wenn Sie ein Microsoft ADO App sind, sind Sie wahrscheinlich einen Verbindungspool mit ....

+1

Im Allgemeinen geht Pooling sehr glücklich damit um ... und nicht nur für das Web. –

+0

Ok, ich das Wort „web“ –

8

Für die automatisierten Testzwecke es in der Regel einfacher ist es in zu übergeben. Dies wird dependency injection genannt.

Wenn Sie Tests schreiben müssen, können Sie ein Pseudo-Datenbankverbindungsobjekt erstellen und dieses anstelle des echten übergeben. Auf diese Weise werden Ihre automatisierten Tests nicht auf einer tatsächlichen Datenbank beruhen, die jedes Mal mit Daten neu gefüllt werden muss.

+1

Thread-Lokalspeicher entfernt diese lösen, ohne in der Anwendung auf jedem Verfahren zwei zusätzliche params zu benötigen –

1

Hier ist ein wenig mehr Einblick in dieses Problem. Ich habe eine Klasse, die DB-Verbindungen verwaltet, und 2 Klassen, die eine Schnittstelle implementieren. Eine der Klassen ist für SQL und die andere für OLAP. Der Manager ist derjenige, der weiß, welche Verbindung zu verwenden ist, damit er die genaue Verbindung an den Typ übergeben kann, oder der Typ kann seine eigene Verbindung erstellen.

1

Sie können Verbindungsobjekte ohne Probleme übergeben (zum Beispiel ermöglicht Microsoft Enterprise Library statische Methodenaufrufe in einer Verbindung) oder Sie können es extern verwalten bis zu Ihrem Design, es gibt keine direkten technischen Kompromisse.

für Portabilität Vorsicht nicht passieren wird eine bestimmte Verbindung, wenn Ihre Lösung auf andere Datenbanken portiert werden (Sie können es eine SqlConnection Bedeutung DO NOT passieren planen mit anderen Datenbanken arbeiten)

9

Persönlich mag ich einen Stapel meiner aktuellen offenen Verbindung und Transaktionen auf der Thread Local Storage mit SetData und GetData speichern.Ich definiere eine Klasse, die meine Verbindungen zur Datenbank verwaltet und es erlaubt, das Verfügungsmuster zu verwenden. Dies erspart mir die Notwendigkeit, Verbindungen und Transaktionen zu übergeben, was den Code verschleiert und verkompliziert.

Ich würde dringend empfehlen, gegen es den Methoden zu offen zu lassen Verbindungen jedes Mal, wenn sie Daten benötigen. Es wird zu einer wirklich schlechten Situation führen, in der es schwierig ist, Transaktionen in der gesamten Anwendung zu verwalten und zu viele Verbindungen zu öffnen und zu schließen (ich weiß über Verbindungs-Pooling, es ist immer noch teurer, eine Verbindung aus dem Pool nachzuschlagen, als sie ist) wiederzuverwenden ein Objekt)

ich am Ende also mit etwas in diese Richtung (total ungetestet):

class DatabaseContext : IDisposable { 

    List<DatabaseContext> currentContexts; 
    SqlConnection connection; 
    bool first = false; 

    DatabaseContext (List<DatabaseContext> contexts) 
    { 
     currentContexts = contexts; 
     if (contexts.Count == 0) 
     { 
      connection = new SqlConnection(); // fill in info 
      connection.Open(); 
      first = true; 
     } 
     else 
     { 
      connection = contexts.First().connection; 
     } 

     contexts.Add(this); 
    } 

    static List<DatabaseContext> DatabaseContexts { 
     get 
     { 
      var contexts = CallContext.GetData("contexts") as List<DatabaseContext>; 
      if (contexts == null) 
      { 
       contexts = new List<DatabaseContext>(); 
       CallContext.SetData("contexts", contexts); 
      } 
      return contexts; 
     } 
    } 

    public static DatabaseContext GetOpenConnection() 
    { 
     return new DatabaseContext(DatabaseContexts); 
    } 


    public SqlCommand CreateCommand(string sql) 
    { 
     var cmd = new SqlCommand(sql); 
     cmd.Connection = connection; 
     return cmd; 
    } 

    public void Dispose() 
    { 
     if (first) 
     { 
      connection.Close(); 
     } 
     currentContexts.Remove(this); 
    } 
} 



void Test() 
{ 
    // connection is opened here 
    using (var ctx = DatabaseContext.GetOpenConnection()) 
    { 
     using (var cmd = ctx.CreateCommand("select 1")) 
     { 
      cmd.ExecuteNonQuery(); 
     } 

     Test2(); 
    } 
    // closed after dispose 
} 

void Test2() 
{ 
    // reuse existing connection 
    using (var ctx = DatabaseContext.GetOpenConnection()) 
    { 
     using (var cmd = ctx.CreateCommand("select 2")) 
     { 
      cmd.ExecuteNonQuery(); 
     } 
    } 
    // leaves connection open 
} 
+0

Aus Neugier, was verhindert, dass der Aufruf von Dispose() in Test2 die in Test geöffnete Verbindung schließt? Ich nehme an, dass DatabaseContext die Anzahl der Clients, die nach der Verbindung gefragt haben, im Auge behalten und nur zulassen würde, dass Dispose die Verbindung schließt, wenn nur eine Anfrage offen ist. Daraus folgt, dass Dispose auch die Anzahl der Clients in DatabaseContext reduzieren würde. Scheint wie eine Gelegenheit für übermäßige Kopplung (könnte wahrscheinlich behoben werden). Was passiert auch, wenn Sie einen Trans über Threads teilen müssen? – xero

+0

@ Xero, Trans über Threads ist eine ziemlich seltene Bedingung, so dass Sie es manuell behandeln.Es ist ein ziemlich gefährliches Spiel zu spielen. Wenn Sie einen Kontext erstellen, weiß dieser, ob er der Verbindungsbesitzer ist oder nicht und dann disponiert er entsprechend –

1

ich würde vorschlagen, dass Sie zwischen dem Verbindungsobjekt und seinem Zustand (offen, geschlossen) unterscheiden.

Sie können eine einzelne Methode (oder Eigenschaft), die die Verbindungszeichenfolge von web.config liest. Wenn Sie jedes Mal die gleiche Version der Verbindungszeichenfolge verwenden, können Sie vom Verbindungs-Pooling profitieren.

Rufen Sie diese Methode auf, wenn Sie eine Verbindung öffnen müssen. Öffnen Sie im letzten Moment nach dem Einrichten aller SqlCommand-Eigenschaften die Verbindung, verwenden Sie sie und schließen Sie sie dann. In C# können Sie mithilfe der using-Anweisung sicherstellen, dass die Verbindung geschlossen ist. Wenn nicht, schließe die Verbindung in einem finally-Block.

Verwandte Themen