Какво става там?
Цитирате списъците с параметри за няколко претоварвания на Add
. Това са удобни методи, които отговарят директно на претоварванията на конструктора за SqlParameter
клас. Те по същество конструират параметърния обект, използвайки конструктор, който има същия подпис като извикания от вас метод за удобство и след това извикват SqlParameterCollection.Add(SqlParameter)
така:
SqlParameter foo = new SqlParameter(parameterName, dbType, size);
this.Add(foo);
AddWithValue
е подобно, но улеснява още повече, като също така задава стойността. Въпреки това, той всъщност беше въведен, за да се отстрани недостатък в рамката. За да цитирам MSDN,
Претоварването на
Add
който приема astring и обектът е отхвърлен поради възможна неяснота сSqlParameterCollection.Add
overload, който приемаString
иSqlDbType
стойност на изброяване, където предаването на цяло число с низа може да се интерпретира като стойност на параметъра или съответнияSqlDbType
стойност. ИзползвайтеAddWithValue
всеки път, когато искате да добавите параметър, като посочите неговото име и стойност.
Конструкторът претоварва за SqlParameter
class са просто удобства за задаване на свойства на инстанция. Те съкращават кода с незначително въздействие върху производителността:конструкторът може да заобиколи методите за настройка и да работи директно върху частни членове. Ако има разлика, няма да е много.
Какво трябва да направя?
Обърнете внимание на следното (от MSDN)
За двупосочни и изходни параметри и връщани стойности, трябва да зададете стойността на
Size
. Това не се изисква за входни параметри и ако не е изрично зададено, стойността се извежда от действителния размер на посочения параметър, когато се изпълнява параметризиран оператор.
Типът по подразбиране е вход. Въпреки това, ако позволите размерът да бъде изведен по този начин и рециклирате обекта на параметъра в цикъл (вие казахте, че сте загрижени за производителността), тогава размерът ще бъде зададен от първата стойност и всички следващи стойности, които са по-дълги, ще бъдат подрязани. Очевидно това е важно само за стойности с променлива дължина, като например низове.
Ако предавате един и същ логически параметър многократно в цикъл, препоръчвам ви да създадете обект SqlParameter извън цикъла и да го оразмерите по подходящ начин. Преоразмеряването на varchar е безвредно, така че ако е PITA, за да получите точния максимум, просто го задайте по-голям, отколкото някога очаквате да бъде колоната. Тъй като рециклирате обекта, вместо да създавате нов за всяка итерация, консумацията на памет за продължителността на цикъла вероятно ще спадне дори и малко да се вълнувате от големия размер.
Честно казано, освен ако не обработите хиляди обаждания, нищо от това няма да има голяма разлика. AddWithValue
създава нов обект, заобикаляйки проблема с оразмеряването. Той е кратък, сладък и лесен за разбиране. Ако преглеждате хиляди, използвайте моя подход. Ако не го направите, използвайте AddWithValue
за да поддържате кода си прост и лесен за поддръжка.
2008 г. беше много отдавна
През годините, откакто написах това, светът се промени. Има нови видове дати, а има и проблем, който не ми е минавал през ума, докато скорошен проблем с датите не ме накара да се замисля за последиците от разширяването.
Разширяването и стесняването, за тези, които не са запознати с термините, са качества на преобразуването на типове данни. Ако присвоите int на double, няма загуба на прецизност, защото double е "по-широк". Винаги е безопасно да направите това, така че преобразуването е автоматично. Ето защо можете да присвоите int на double, но ако отидете по друг начин, трябва да направите изрично прехвърляне - double към int е стеснително преобразуване с потенциална загуба на прецизност.
Това може да важи за низове:NVARCHAR е по-широк от VARCHAR, така че можете да присвоите VARCHAR на NVARCHAR, но преминаването по другия начин изисква прехвърляне. Сравнението работи, защото VARCHAR имплицитно се разширява до NVARCHAR, но това ще попречи на използването на индекси!
C# низовете са Unicode, така че AddWithValue ще произведе параметър NVARCHAR. В другия край стойностите на колоната VARCHAR се разширяват до NVARCHAR за сравнение. Това не спира изпълнението на заявката, но предотвратява използването на индекси. Това е лошо.
Какво можете да направите за това? Имате две възможни решения.
- Въведете изрично параметъра. Това означава, че няма повече AddWithValue
- Променете всички типове колони с низове на NVARCHAR.
Изхвърлянето на VARCHAR е може би най-добрата идея. Това е проста промяна с предвидими последствия и подобрява историята ви за локализация. Възможно е обаче да нямате това като опция.
Тези дни не правя много директен ADO.NET. Linq2Sql сега е моето предпочитано оръжие и актът на написването на тази актуализация ме накара да се чудя как се справя с този проблем. Имам внезапно, изгарящо желание да проверя кода си за достъп до данни за търсене чрез колони VARCHAR.
2019 г. и светът се придвижи отново
Linq2Sql не е наличен в dotnet Core, така че аз използвам Dapper. Проблемът [N]VARCHAR все още е нещо, но вече не е погребан досега. Вярвам, че може да се използва и ADO, така че нещата са завършили пълен кръг в това отношение.