sql >> Database >  >> RDS >> Sqlserver

Wat is de beste methode om parameters door te geven aan SQLCommand?

Wat is daar aan de hand?

U citeert de parameterlijsten voor verschillende overbelastingen van Add . Dit zijn gemaksmethoden die rechtstreeks overeenkomen met constructoroverbelastingen voor de SqlParameter klas. Ze construeren in wezen het parameterobject met behulp van een constructor die dezelfde handtekening heeft als de gemaksmethode die u hebt aangeroepen, en roepen vervolgens SqlParameterCollection.Add(SqlParameter) aan. zoals dit:

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

AddWithValue is vergelijkbaar, maar neemt het gemak nog verder, ook door de waarde in te stellen. Het is echter eigenlijk geïntroduceerd om een ​​​​frameworkfout op te lossen. Om MSDN te citeren,

De overbelasting van Add waarvoor astring nodig is en een object is verouderd vanwege mogelijke ambiguïteit met deSqlParameterCollection.Add overbelastingdat duurt een String en een SqlDbType opsommingswaarde waarbij het doorgeven van een geheel getal met de tekenreeks kan worden geïnterpreteerd als ofwel de parameterwaarde of het corresponderendeSqlDbType waarde. Gebruik AddWithValue wanneer u een parameter wilt toevoegen door de naam en waarde op te geven.

De constructor overbelast voor de SqlParameter class zijn louter gemakken voor het instellen van instantie-eigenschappen. Ze verkorten de code, met een marginale impact op de prestaties:de constructor kan setter-methoden omzeilen en rechtstreeks werken met privéleden. Als er een verschil is, zal het niet veel zijn.

Wat moet ik doen?

Let op het volgende (van MSDN)

Voor bidirectionele en uitvoerparameters, en retourwaarden, moet u de waarde van Size instellen . Dit is niet vereist voor invoerparameters, en indien niet expliciet ingesteld, wordt de waarde afgeleid van de werkelijke grootte van de opgegeven parameter wanneer een geparametriseerde instructie wordt uitgevoerd.

Het standaardtype is invoer. Als u echter toestaat dat de grootte op deze manier wordt afgeleid en u het parameterobject in een lus recyclet (u zei wel dat u zich zorgen maakte over de prestaties), dan wordt de grootte ingesteld door de eerste waarde en eventuele volgende waarden die langer zijn, worden geknipt. Uiteraard is dit alleen van belang voor waarden met variabele lengte, zoals strings.

Als u dezelfde logische parameter herhaaldelijk in een lus doorgeeft, raad ik u aan een SqlParameter-object buiten de lus te maken en de juiste grootte te geven. Het te groot maken van een varchar is ongevaarlijk, dus als het een PITA is om het exacte maximum te krijgen, stelt u het gewoon groter in dan u ooit van de kolom verwacht. Omdat u het object recyclet in plaats van voor elke iteratie een nieuwe te maken, zal het geheugenverbruik gedurende de duur van de lus waarschijnlijk dalen zelfs als je een beetje opgewonden raakt van de overmaat.

Eerlijk is eerlijk, tenzij u duizenden oproepen verwerkt, zal dit allemaal niet veel uitmaken. AddWithValue creëert een nieuw object, waarbij het formaatprobleem wordt omzeild. Het is kort en krachtig en gemakkelijk te begrijpen. Als je duizenden doorloopt, gebruik dan mijn aanpak. Als je dat niet doet, gebruik dan AddWithValue om uw code eenvoudig en gemakkelijk te onderhouden te houden.

2008 is lang geleden

In de jaren sinds ik dit schreef, is de wereld veranderd. Er zijn nieuwe soorten datums, en er is ook een probleem dat niet bij me opkwam totdat een recent probleem met datums me deed nadenken over de implicaties van verruiming.

Verbreding en vernauwing, voor degenen die niet bekend zijn met de termen, zijn eigenschappen van conversies van gegevenstypen. Als je een int toewijst aan een double, is er geen verlies aan precisie omdat double "breder" is. Het is altijd veilig om dit te doen, dus conversie is automatisch. Dit is de reden waarom je een int aan een double kunt toewijzen, maar als je de andere kant op gaat, moet je een expliciete cast doen - double naar int is een versmallende conversie met mogelijk verlies van precisie.

Dit kan van toepassing zijn op strings:NVARCHAR is breder dan VARCHAR, dus je kunt een VARCHAR toewijzen aan een NVARCHAR, maar om de andere kant op te gaan, is een cast nodig. Vergelijking werkt omdat de VARCHAR impliciet breder wordt naar NVARCHAR, maar dit zal het gebruik van indexen belemmeren!

C#-tekenreeksen zijn Unicode, dus AddWithValue zal een NVARCHAR-parameter produceren. Aan de andere kant worden de VARCHAR-kolomwaarden uitgebreid tot NVARCHAR ter vergelijking. Dit stopt de uitvoering van query's niet, maar voorkomt dat indexen worden gebruikt. Dit is slecht.

Wat kun je eraan doen? Je hebt twee mogelijke oplossingen.

  • Typ de parameter expliciet. Dit betekent geen AddWithValue meer
  • Wijzig alle typen tekenreekskolommen in NVARCHAR.

Het dumpen van VARCHAR is waarschijnlijk het beste idee. Het is een simpele verandering met voorspelbare gevolgen en het verbetert uw lokalisatieverhaal. Het is echter mogelijk dat u dit niet als optie heeft.

Tegenwoordig doe ik niet veel direct ADO.NET. Linq2Sql is nu mijn favoriete wapen en het schrijven van deze update heeft me doen afvragen hoe het met dit probleem omgaat. Ik heb een plotselinge, brandende wens om mijn gegevenstoegangscode te controleren op zoekopdrachten via VARCHAR-kolommen.

2019 en de wereld is opnieuw verder gegaan

Linq2Sql is niet beschikbaar in dotnet Core, dus ik merk dat ik Dapper gebruik. Het [N]VARCHAR-probleem is nog steeds een ding, maar het is tot nu toe niet langer begraven. Ik geloof dat je ook ADO kunt gebruiken, dus in dat opzicht is de cirkel rond.



  1. Index voor het vinden van een element in een JSON-array

  2. Hoe ORDER BY-clausule in SQL te gebruiken?

  3. Hoe de functie MAKE_SET() werkt in MySQL

  4. Wat is er nieuw in PostgreSQL 11