Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Qual è il metodo migliore per passare i parametri a SQLCommand?

Cosa sta succedendo lì dentro?

Citare gli elenchi di parametri per diversi overload di Add . Si tratta di metodi pratici che corrispondono direttamente agli overload del costruttore per SqlParameter classe. Essenzialmente costruiscono l'oggetto parametro usando qualunque costruttore abbia la stessa firma del metodo di convenienza che hai chiamato, quindi chiamano SqlParameterCollection.Add(SqlParameter) così:

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

AddWithValue è simile ma porta la comodità ancora di più, impostando anche il valore. Tuttavia, è stato effettivamente introdotto per risolvere un difetto del framework. Per citare MSDN,

Il sovraccarico di Add che accetta una stringa e un oggetto è stato deprecato a causa di una possibile ambiguità con SqlParameterCollection.Add overloadthat accetta una String e un SqlDbType valore di enumerazione in cui il passaggio di un intero con la stringa potrebbe essere interpretato come il valore del parametro o il corrispondente SqlDbType valore. Usa AddWithValue ogni volta che vuoi aggiungere un parametro specificandone nome e valore.

Il costruttore esegue l'overload di SqlParameter class sono semplici comodità per impostare le proprietà dell'istanza. Accorciano il codice, con un impatto marginale sulle prestazioni:il costruttore può aggirare i metodi setter e operare direttamente sui membri privati. Se c'è una differenza non sarà molto.

Cosa devo fare?

Nota quanto segue (da MSDN)

Per i parametri bidirezionali e di output e i valori restituiti, devi impostare il valore di Size . Ciò non è richiesto per i parametri di input e, se non è impostato in modo esplicito, il valore viene dedotto dalla dimensione effettiva del parametro specificato quando viene eseguita un'istruzione parametrizzata.

Il tipo predefinito è input. Tuttavia, se si consente che la dimensione venga dedotta in questo modo e si ricicla l'oggetto parametro in un ciclo (hai detto che eri preoccupato per le prestazioni), la dimensione verrà impostata dal primo valore e tutti i valori successivi più lunghi saranno tagliato. Ovviamente questo è significativo solo per valori di lunghezza variabile come le stringhe.

Se stai passando lo stesso parametro logico ripetutamente in un ciclo, ti consiglio di creare un oggetto SqlParameter al di fuori del ciclo e ridimensionarlo in modo appropriato. Il sovradimensionamento di un varchar è innocuo, quindi se è un PITA per ottenere il massimo esatto, impostalo più grande di quanto ti aspetti che sia la colonna. Poiché stai riciclando l'oggetto anziché crearne uno nuovo per ogni iterazione, è probabile che il consumo di memoria per la durata del ciclo cali anche se ti ecciti un po' con il sovradimensionamento.

A dire il vero, a meno che non elabori migliaia di chiamate, niente di tutto ciò farà molta differenza. AddWithValue crea un nuovo oggetto, aggirando il problema del dimensionamento. È breve, dolce e facile da capire. Se ne scorgi migliaia, usa il mio approccio. Se non lo fai, usa AddWithValue per mantenere il tuo codice semplice e facile da mantenere.

Il 2008 è stato tanto tempo fa

Negli anni da quando ho scritto questo, il mondo è cambiato. Ci sono nuovi tipi di date, e c'è anche un problema che non mi è passato per la mente fino a quando un recente problema con le date non mi ha fatto pensare alle implicazioni dell'allargamento.

L'allargamento e il restringimento, per chi non ha familiarità con i termini, sono qualità delle conversioni dei tipi di dati. Se assegni un int a un double, non c'è perdita di precisione perché double è "più ampio". È sempre sicuro farlo, quindi la conversione è automatica. Questo è il motivo per cui puoi assegnare un int a un double ma andando dall'altra parte devi eseguire un cast esplicito:da double a int è una conversione restringente con potenziale perdita di precisione.

Questo può applicarsi alle stringhe:NVARCHAR è più largo di VARCHAR, quindi puoi assegnare un VARCHAR a un NVARCHAR ma andare dall'altra parte richiede un cast. Il confronto funziona perché VARCHAR si allarga implicitamente a NVARCHAR, ma questo interferirà con l'uso degli indici!

Le stringhe C# sono Unicode, quindi AddWithValue produrrà un parametro NVARCHAR. All'altra estremità, i valori della colonna VARCHAR si allargano a NVARCHAR per il confronto. Ciò non interrompe l'esecuzione della query ma impedisce l'utilizzo degli indici. Questo è male.

Cosa puoi fare al riguardo? Hai due possibili soluzioni.

  • Digitare esplicitamente il parametro. Questo significa niente più AddWithValue
  • Cambia tutti i tipi di colonne di stringhe in NVARCHAR.

Abbandonare VARCHAR è probabilmente l'idea migliore. È un semplice cambiamento con conseguenze prevedibili e migliora la tua storia di localizzazione. Tuttavia, potresti non averlo come opzione.

In questi giorni non faccio molto ADO.NET diretto. Linq2Sql è ora la mia arma preferita e l'atto di scrivere questo aggiornamento mi ha lasciato chiedendomi come gestisce questo problema. Ho un desiderio improvviso e ardente di controllare il mio codice di accesso ai dati per la ricerca tramite le colonne VARCHAR.

2019 e il mondo è andato di nuovo

Linq2Sql non è disponibile in dotnet Core, quindi mi ritrovo a usare Dapper. Il problema [N]VARCHAR è ancora una cosa ma non è più così sepolto. Credo che si possa anche usare ADO, quindi le cose hanno chiuso il cerchio al riguardo.