it-swarm.com.de

Was ist die beste Methode, um Parameter an SQLCommand zu übergeben?

Was ist die beste Methode, um Parameter an SQLCommand zu übergeben? Du kannst tun:

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

oder

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

oder

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

Es scheint, als ob der erste in Bezug auf die Leistung oder die Fehlerprüfung irgendwie "besser" ist. Ich würde es aber gerne genauer wissen.

54
TAG

Sie können auch AddWithValue() verwenden, müssen sich jedoch der Möglichkeit einer falschen impliziten Typkonvertierung bewusst sein.

cmd.Parameters.AddWithValue("@Name", "Bob");
52
Mitch Wheat

Was ist da drin los?

Sie zitieren die Parameterlisten für mehrere Überladungen von Add. Hierbei handelt es sich um praktische Methoden, die Konstruktorüberladungen für die Klasse SqlParameter direkt entsprechen. Sie konstruieren das Parameterobjekt im Wesentlichen mit dem Konstruktor, der dieselbe Signatur wie die von Ihnen aufgerufene Convenience-Methode hat, und rufen dann SqlParameterCollection.Add(SqlParameter) wie folgt auf:

SqlParameter foo = new SqlParameter(parameterName, dbType, size);
this.Add(foo);

AddWithValue ist ähnlich, geht aber noch komfortabler vor sich und legt auch den Wert fest. Es wurde jedoch tatsächlich eingeführt, um einen Rahmenfehler zu beheben. Um MSDN zu zitieren,

Die Überladung von Add, die eine Zeichenfolge und ein Objekt enthält, wurde wegen möglicher Mehrdeutigkeit mit SqlParameterCollection.Add Überladung, die einen String und einen SqlDbType Aufzählungswert annimmt, wobei die Übergabe einer Ganzzahl mit der Zeichenfolge entweder als Parameterwert oder als entsprechender SqlDbType Wert interpretiert werden könnte. Verwenden Sie AddWithValue, wenn Sie einen Parameter durch Angabe seines Namens und Werts hinzufügen möchten.

Die Konstruktorüberladungen für die SqlParameter -Klasse sind lediglich eine Annehmlichkeit zum Festlegen von Instanzeigenschaften. Sie verkürzen den Code, was sich geringfügig auf die Leistung auswirkt: Der Konstruktor kann die Setter-Methoden umgehen und direkt auf private Member zugreifen. Wenn es einen Unterschied gibt, wird es nicht viel sein.

Was soll ich machen?

Beachten Sie Folgendes (von MSDN)

Für bidirektionale Parameter, Ausgabeparameter und Rückgabewerte müssen Sie den Wert von Size festlegen. Dies ist für Eingabeparameter nicht erforderlich. Wenn dies nicht explizit festgelegt ist, wird der Wert aus der tatsächlichen Größe des angegebenen Parameters abgeleitet, wenn eine parametrisierte Anweisung ausgeführt wird.

Der Standardtyp ist input. Wenn Sie jedoch zulassen, dass die Größe wie folgt abgeleitet wird, und Sie das Parameterobjekt in einer Schleife wiederverwenden (Sie haben gesagt, dass Sie sich mit der Leistung befassen), wird die Größe durch den ersten Wert festgelegt, und alle nachfolgenden Werte, die länger sind, werden übernommen abgeschnitten. Dies ist offensichtlich nur für Werte mit variabler Länge wie Zeichenfolgen von Bedeutung.

Wenn Sie denselben logischen Parameter in einer Schleife wiederholt übergeben, empfiehlt es sich, ein SqlParameter-Objekt außerhalb der Schleife zu erstellen und die Größe entsprechend anzupassen. Eine Überdimensionierung eines Varchars ist harmlos. Wenn es sich also um ein PITA handelt, um das genaue Maximum zu erhalten, stellen Sie es einfach größer ein, als Sie es jemals erwartet haben. Da Sie das Objekt recyceln, anstatt für jede Iteration ein neues zu erstellen, wird der Speicherbedarf über die Dauer der Schleife wahrscheinlich drop sein, auch wenn Sie mit der Übergröße ein wenig aufgeregt sind.

Um ehrlich zu sein, wenn Sie nicht Tausende von Anrufen bearbeiten, wird dies keinen großen Unterschied machen. AddWithValue erstellt ein neues Objekt und umgeht das Größenproblem. Es ist kurz und süß und leicht zu verstehen. Wenn Sie Tausende durchlaufen, verwenden Sie meinen Ansatz. Wenn nicht, verwenden Sie AddWithValue, um Ihren Code einfach und pflegeleicht zu halten.


2008 ist lange her

In den Jahren, seit ich das geschrieben habe, hat sich die Welt verändert. Es gibt neue Arten von Datumsangaben, und es gibt auch ein Problem, das mir erst in den Sinn gekommen ist, als ich kürzlich über die Auswirkungen einer Erweiterung nachdachte.

Erweitern und Verengen sind für diejenigen, die mit den Begriffen nicht vertraut sind, Eigenschaften von Datentypkonvertierungen. Wenn Sie einem Double ein Int zuweisen, geht keine Genauigkeit verloren, da Double "breiter" ist. Dies ist immer sicher, daher erfolgt die Konvertierung automatisch. Aus diesem Grund können Sie einem Double ein int zuweisen, aber in umgekehrter Richtung müssen Sie ein explizites Cast ausführen - double to int ist eine Verengungskonvertierung mit potenziellem Genauigkeitsverlust.

Dies kann auf Zeichenfolgen zutreffen: NVARCHAR ist breiter als VARCHAR, sodass Sie einem NVARCHAR ein VARCHAR zuweisen können, für die Umkehrung ist jedoch eine Umwandlung erforderlich. Der Vergleich funktioniert, weil sich VARCHAR implizit zu NVARCHAR erweitert dies beeinträchtigt jedoch die Verwendung von Indizes!

C # -Strings sind Unicode, daher erzeugt AddWithValue einen NVARCHAR-Parameter. Am anderen Ende erweitern sich die VARCHAR-Spaltenwerte zu Vergleichszwecken auf NVARCHAR. Dies stoppt die Ausführung der Abfrage nicht, verhindert jedoch die Verwendung von Indizes. Das ist schlecht.

Was können Sie dagegen tun? Sie haben zwei mögliche Lösungen.

  • Geben Sie den Parameter explizit ein. Dies bedeutet kein AddWithValue mehr
  • Ändern Sie alle Zeichenfolgenspaltentypen in NVARCHAR.

VARCHAR fallen zu lassen ist wahrscheinlich die beste Idee. Es ist eine einfache Änderung mit vorhersehbaren Folgen und verbessert Ihre Lokalisierungsgeschichte. Möglicherweise haben Sie dies jedoch nicht als Option.

In diesen Tagen mache ich nicht viel direktes ADO.NET. Linq2Sql ist jetzt meine Waffe der Wahl, und beim Schreiben dieses Updates habe ich mich gefragt, wie es mit diesem Problem umgeht. Ich habe plötzlich das brennende Verlangen, meinen Datenzugriffscode für die Suche über VARCHAR-Spalten zu überprüfen.


2019 und die Welt hat sich weiterentwickelt wieder

Linq2Sql ist in Dotnet Core nicht verfügbar, daher verwende ich Dapper. Das [N] VARCHAR-Problem ist immer noch eine Sache, aber es ist nicht mehr so ​​weit begraben. Ich glaube, man kann auch ADO verwenden, also hat sich der Kreis in dieser Hinsicht geschlossen.

61
Peter Wone

Ich würde mit Sicherheit # 1 sagen. Microsoft macht es jedoch im Datenzugriffsanwendungsblock in der Unternehmensbibliothek am besten, insbesondere für SQL Server:

http://msdn.Microsoft.com/en-us/library/dd203144.aspx

5
Booji Boy

Früher habe ich Ihre Option 1 verwendet:

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

das hat gut funktioniert, aber dann habe ich angefangen .AddWithValue zu verwenden und es ist so einfach wie es nur geht. Es hat mir nach vielen, vielen tausend Einsätzen kein Problem bereitet. Wohlgemerkt, ich übergebe meine Klassen fast immer an private Variablen, so dass ich mich nicht so sehr um die implizite Typkonvertierung kümmern muss.

4
aSkywalker

Das hängt von Ihrer Anwendung ab. Ich mag eigentlich 2, weil ich mein DAO nicht ändern muss, wenn ich die Länge eines gespeicherten proc-Parameters ändere. Das bin aber nur ich. Ich weiß nicht, ob es irgendwelche Leistungsnachteile gibt.

3
Charles Graham