Was ist da drin los?
Sie zitieren die Parameterlisten für mehrere Überladungen von Add
. Dies sind praktische Methoden, die direkt Konstruktorüberladungen für den SqlParameter
entsprechen Klasse. Sie konstruieren im Wesentlichen das Parameterobjekt mit einem beliebigen Konstruktor, der dieselbe Signatur wie die von Ihnen aufgerufene Hilfsmethode hat, und rufen dann SqlParameterCollection.Add(SqlParameter)
auf so:
SqlParameter foo = new SqlParameter(parameterName, dbType, size);
this.Add(foo);
AddWithValue
ist ähnlich, geht aber noch komfortabler und setzt auch den Wert. Tatsächlich wurde es jedoch eingeführt, um einen Framework-Fehler zu beheben. Um MSDN zu zitieren,
Die Überladung von Add
die einen String und ein Objekt akzeptiert, wurde wegen möglicher Mehrdeutigkeit mit SqlParameterCollection.Add
als veraltet markiert überladen, das einen String
benötigt und ein SqlDbType
Enumerationswert, bei dem das Übergeben einer Ganzzahl mit der Zeichenfolge entweder als Parameterwert oder als der entsprechende SqlDbType
interpretiert werden könnte Wert. Verwenden Sie AddWithValue
wann immer Sie einen Parameter hinzufügen möchten, indem Sie seinen Namen und Wert angeben.
Der Konstruktor wird für den SqlParameter
überladen -Klasse sind lediglich Hilfsmittel zum Festlegen von Instanzeigenschaften. Sie verkürzen den Code mit geringfügigen Auswirkungen auf die Leistung:Der Konstruktor kann Setter-Methoden umgehen und direkt mit privaten Membern arbeiten. Wenn es einen Unterschied gibt, wird es nicht viel sein.
Was soll ich tun?
Beachten Sie Folgendes (von MSDN)
Für bidirektionale und Ausgabeparameter und Rückgabewerte müssen Sie den Wert von Size
festlegen . Dies ist für Eingabeparameter nicht erforderlich, und wenn es nicht explizit gesetzt ist, wird der Wert von der tatsächlichen Größe des angegebenen Parameters abgeleitet, wenn eine parametrisierte Anweisung ausgeführt wird.
Der Standardtyp ist Eingabe. Wenn Sie jedoch zulassen, dass die Größe auf diese Weise abgeleitet wird, und Sie das Parameterobjekt in einer Schleife wiederverwenden (Sie sagten, dass Sie sich um die Leistung kümmern), wird die Größe durch den ersten Wert festgelegt, und alle nachfolgenden Werte, die länger sind, werden festgelegt abgeschnitten. Offensichtlich ist dies nur für Werte mit variabler Länge wie Strings von Bedeutung.
Wenn Sie denselben logischen Parameter wiederholt in einer Schleife übergeben, empfehle ich Ihnen, ein SqlParameter-Objekt außerhalb der Schleife zu erstellen und es entsprechend zu dimensionieren. Das Überdimensionieren eines Varchar 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 jemals von der Spalte erwarten würden. Da Sie das Objekt recyceln, anstatt für jede Iteration ein neues zu erstellen, wird der Speicherverbrauch während der Dauer der Schleife wahrscheinlich sinken auch wenn dich die Überdimensionierung etwas aufregt.
Um ehrlich zu sein, es sei denn, Sie bearbeiten Tausende von Anrufen, nichts davon wird einen großen Unterschied machen. AddWithValue
erstellt ein neues Objekt und umgeht das Größenproblem. Es ist kurz und bündig und leicht zu verstehen. Wenn Sie Tausende durchlaufen, verwenden Sie meinen Ansatz. Wenn nicht, verwenden Sie AddWithValue
um Ihren Code einfach und wartungsfreundlich zu halten.
2008 ist lange her
In den Jahren, seit ich dies geschrieben habe, hat sich die Welt verändert. Es gibt neue Arten von Datteln, und es gibt auch ein Problem, das mir nicht in den Sinn kam, bis mich ein kürzlich aufgetretenes Problem mit Datteln dazu brachte, über die Auswirkungen der Erweiterung nachzudenken.
Erweitern und Verengen sind für diejenigen, die mit den Begriffen nicht vertraut sind, Qualitäten von Datentypkonvertierungen. Wenn Sie einem Double ein Int zuweisen, gibt es keinen Genauigkeitsverlust, 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 die andere Richtung müssen Sie eine explizite Umwandlung durchführen - Double in Int ist eine einschränkende Konvertierung mit potenziellem Genauigkeitsverlust.
Dies kann auf Zeichenfolgen zutreffen:NVARCHAR ist breiter als VARCHAR, sodass Sie einem NVARCHAR einen VARCHAR zuweisen können, aber der umgekehrte Weg erfordert eine Umwandlung. Der Vergleich funktioniert, weil VARCHAR implizit zu NVARCHAR erweitert wird, aber dies wird die Verwendung von Indizes beeinträchtigen!
C#-Strings sind Unicode, daher erzeugt AddWithValue einen NVARCHAR-Parameter. Am anderen Ende erweitern sich VARCHAR-Spaltenwerte zum Vergleich auf NVARCHAR. Dadurch wird die Abfrageausführung nicht gestoppt, aber es wird verhindert, dass Indizes verwendet werden. Das ist schlecht.
Was können Sie dagegen tun? Sie haben zwei mögliche Lösungen.
- Geben Sie den Parameter explizit ein. Das bedeutet kein AddWithValue mehr
- Ändern Sie alle Zeichenfolgenspaltentypen in NVARCHAR.
Das Ablegen von VARCHAR ist wahrscheinlich die beste Idee. Es ist eine einfache Änderung mit vorhersehbaren Folgen und verbessert Ihre Lokalisierungsstory. Möglicherweise haben Sie dies jedoch nicht als Option.
Heutzutage mache ich nicht viel direktes ADO.NET. Linq2Sql ist jetzt meine bevorzugte Waffe, und beim Schreiben dieses Updates frage ich mich, wie es mit diesem Problem umgeht. Ich habe plötzlich den brennenden Wunsch, meinen Datenzugriffscode für die Suche über VARCHAR-Spalten zu überprüfen.
2019 und die Welt hat sich wieder weiterentwickelt
Linq2Sql ist in dotnet Core nicht verfügbar, daher verwende ich Dapper. Das [N]VARCHAR-Problem besteht immer noch, aber es ist nicht mehr so weit begraben. Ich glaube, man kann auch ADO verwenden, also schließt sich der Kreis in dieser Hinsicht.