2011-01-07 11 views
35

Es gibt eine weitere Frage dazu:Wann sollten "SqlDbType" und "size" beim Hinzufügen von SqlCommand-Parametern verwendet werden?

What's the best method to pass parameters to SQLCommand?

Aber ich bin zu wollen wissen, was die Unterschiede sind und wenn es irgendwelche Probleme mit den verschiedenen Möglichkeiten.

Normalerweise verwende ich eine Struktur, etwa wie folgt:

using (SqlConnection conn = new SqlConnection(connectionString)) 
using (SqlCommand cmd = new SqlCommand(SQL, conn)) 
{ 
    cmd.CommandType = CommandType.Text; 
    cmd.CommandTimeout = Settings.Default.reportTimeout; 
    cmd.Parameters.Add("type", SqlDbType.VarChar, 4).Value = type; 

    cmd.Connection.Open(); 

    using (SqlDataAdapter adapter = new SqlDataAdapter(cmd)) 
    { 
     adapter.Fill(ds); 
    } 
     //use data      
} 

Nun gibt es mehrere Möglichkeiten, die cmd Parameter hinzuzufügen, und ich frage mich, was am besten ist:

cmd.Parameters.Add("@Name", SqlDbType.VarChar, 20).Value = "Bob"; 
cmd.Parameters.Add("@Name", SqlDbType.VarChar).Value = "Bob"; 
cmd.Parameters.Add("@Name").Value = "Bob"; 
cmd.Parameters.AddWithValue("@Name", "Bob"); 

die Länge der Having Feld in der Weitergabe der Varchars ich nehme an, ist nicht vorzuziehen, da es ein magischer Wert ist, der später in der Datenbank geändert werden kann. Ist das richtig? Wenn irgendein Problem auftritt, das auf diese Weise ein varchar (Leistung oder anderes) passiert, nehme ich an, dass es standardmäßig auf varchar (max) oder die Datenbank entspricht. Ich bin einigermaßen glücklich, dass das funktionieren wird.

Der Teil, der mich mehr betrifft, ist der Verlust der SqlDbType-Enumeration, wenn ich die dritte oder vierte Option verwende, die ich oben aufgeführt habe, stelle ich überhaupt keinen Typ bereit. Gibt es Fälle, wo dies nicht funktioniert Ich kann mir vorstellen, Probleme mit Varchar in Char falsch umgewandelt oder umgekehrt oder vielleicht Probleme mit Dezimal zu Geld ....

In Bezug auf die Datenbank der Feldtyp würde ich sagen viel weniger wahrscheinlich als die Länge zu ändern, ist es also wert, zu behalten?

+3

Während Sie Ihre Frage nicht beantworten, wissen Sie, dass Sie die Verbindung nicht vor dem Aufruf von 'SqlDataAdapter.Fill()' öffnen müssen, und dass es von Vorteil ist, dies nicht zu tun? –

+0

@Rowland guten Punkt. Ich wusste das, obwohl es in meinem Code ein Versehen war. Ich glaube, ich habe den ursprünglichen Codeblock von irgendwo genommen, dass ich einen SqlDataReader nicht einen Adapter verwendet habe (Sie müssen die Verbindung für dieses Recht öffnen?). Das bekommst du für eine ungeeignete Copy/Paste-Programmierung :-). In meinem Code jetzt behoben. – PeteT

+0

nur gedacht, ich würde es erwähnen, wie es ist eine dieser "obskuren Tipps, die Menschen vielleicht nicht wissen" –

Antwort

49

Nach meiner Erfahrung würde ich sicherstellen, dass ich diese Dinge tun:

  • sicher macht es Ihnen, dass der Datentyp für den Parameter definiert. ADO.NET hat einen anständigen Job zu erraten, aber in einigen Fällen kann es schrecklich aus sein - so würde ich diese Methode vermeiden:

    cmd.Parameters.Add("@Name").Value = "Bob"; 
    cmd.Parameters.AddWithValue("@Name", "Bob"); 
    

    ADO.NET Letting denkt, die Art des Parameters durch den Wert übergeben wird, tricky, und wenn es aus irgendeinem Grund aus ist, sind das wirklich knifflige Bugs zu finden und zu finden! Stellen Sie sich vor, was passiert, wenn Sie einen DBNull.Value übergeben - welchen Datentyp sollte ADO.NET dafür wählen?

    Sei einfach explizit - sag, welchen Typ du willst!

  • wenn Sie String-Parameter verwenden, stellen Sie sicher, die Länge explizit definieren - so würde ich diese Methode vermeiden, auch:

    cmd.Parameters.Add("@Name", SqlDbType.VarChar).Value = "Bob"; 
    

    Wenn Sie eine Länge nicht weiter, ADO. NET kann standardmäßig auf einen beliebigen Wert oder auf die Länge der als Wert übergebenen Zeichenfolge oder auf etwas anderes eingestellt werden - Sie sind sich nie ganz sicher. Und wenn Ihre Länge nicht mit dem übereinstimmt, was der gespeicherte Proc wirklich erwartet, sehen Sie möglicherweise Conversion und andere unangenehme Überraschungen. Wenn Sie also einen String definieren, definieren Sie auch dessen Länge!

So in Ihrem Fall der einzige Ansatz, der für mich wirklich funktioniert, ist dieser hier:

cmd.Parameters.Add("@Name", SqlDbType.VarChar, 20).Value = "Bob"; 

, weil es den Datentyp a) definiert explizit zu verwenden, und b) definiert die Länge der Zeichenfolge explizit.

+0

Wenn Sie eine gespeicherte Prozedur verwenden, können Sie nicht nur den Parametertyp aus den Metadaten von erhalten SqlCommandBuilder.DeriveParameters (cmd)? – devinbost

+0

Sollte die übergebene Länge die der zugrunde liegenden Parameterdefinition sein? Und wenn ja, verstößt das nicht gegen DRY? – tbone

4

Durch Hinzufügen des Typs erhöhen Ihre Anforderungen die Leistung, da sie den zwischengespeicherten Abfrageplan verwenden.

Hier ist ein Zitat von MSDN:

Parameterized Befehle können auch Abfrageausführungsleistung verbessern, weil sie der Datenbankserver genau entspricht den eingehenden Befehl mit einem richtigen gecached Abfrage-Plan helfen.

Weitere zu lesen in Execution Plan Caching and Reuse.

+0

Alle Optionen von Pete sind parametrisiert, daher würde ich mich wundern, wenn das Hinzufügen der Parameter auf unterschiedliche Weise die Leistung beeinflusst - es ist sicherlich nicht explizit in dem Artikel erwähnt, mit dem Sie verlinkt haben. –

+4

stimme ich nicht zu. Was der Artikel beschreibt ist, dass durch die Definition des Parameters so genau wie möglich ist es wahrscheinlicher, dass ein Cache-Abfrage-Plan verwendet wird, und dann mit höherer Leistung. Der Unterabschnitt Einfache Parametrisierung besagt Folgendes: In SQL Server erhöht die Verwendung von Parametern oder Parametermarken in Transact-SQL-Anweisungen die Fähigkeit der relationalen Engine, neue SQL-Anweisungen mit vorhandenen, zuvor kompilierten Ausführungsplänen abzugleichen. – StefanE