Co se tam děje?
Uvádíte seznamy parametrů pro několik přetížení Add
. Toto jsou pohodlné metody, které přímo odpovídají přetížení konstruktoru pro SqlParameter
třída. V podstatě zkonstruují objekt parametru pomocí jakéhokoli konstruktoru, který má stejný podpis jako metoda pohodlí, kterou jste zavolali, a poté zavolají SqlParameterCollection.Add(SqlParameter)
takhle:
SqlParameter foo = new SqlParameter(parameterName, dbType, size);
this.Add(foo);
AddWithValue
je podobný, ale posouvá pohodlí ještě dále a také nastavení hodnoty. Ve skutečnosti však byl zaveden, aby vyřešil rámcovou chybu. Chcete-li citovat MSDN,
Přetížení
Add
který používá astring a objekt byl zastaralý z důvodu možné nejednoznačnosti sSqlParameterCollection.Add
přetížení, které vyžadujeString
aSqlDbType
hodnota výčtu, kde by předávání celého čísla s řetězcem mohlo být interpretováno jako hodnota parametru nebo odpovídajícíSqlDbType
hodnota. PoužijteAddWithValue
kdykoli chcete přidat parametr zadáním jeho názvu a hodnoty.
Konstruktor se přetíží pro SqlParameter
třídy jsou pouhými vymoženostmi pro nastavení vlastností instance. Zkracují kód s marginálním dopadem na výkon:konstruktor může obejít metody setter a pracovat přímo se soukromými členy. Pokud existuje rozdíl, nebude velký.
Co mám dělat?
Všimněte si následujícího (z MSDN)
Pro obousměrné a výstupní parametry a návratové hodnoty musíte nastavit hodnotu
Size
. Toto není vyžadováno pro vstupní parametry, a pokud není explicitně nastaveno, je hodnota odvozena ze skutečné velikosti zadaného parametru při provádění parametrizovaného příkazu.
Výchozí typ je input. Pokud však dovolíte, aby velikost byla odvozena takto a objekt parametru recyklujete ve smyčce (říkali jste, že vám jde o výkon), pak bude velikost nastavena první hodnotou a všechny následující hodnoty, které jsou delší, budou oříznuté. To je samozřejmě významné pouze pro hodnoty s proměnnou délkou, jako jsou řetězce.
Pokud opakovaně předáváte stejný logický parametr ve smyčce, doporučuji vytvořit objekt SqlParameter mimo smyčku a vhodně jej upravit. Nadměrná velikost varcharu je neškodná, takže pokud je to PITA, abyste získali přesné maximum, nastavte jej větší, než byste kdy očekávali, že bude sloupec. Protože objekt recyklujete, místo abyste pro každou iteraci vytvořili nový, pravděpodobně poklesne spotřeba paměti po dobu trvání cyklu i když vás to předimenzování trochu vzruší.
Po pravdě řečeno, pokud nezpracujete tisíce hovorů, nic z toho příliš nezmění. AddWithValue
vytvoří nový objekt, čímž se vyhne problému velikosti. Je to krátké a sladké a snadno pochopitelné. Pokud procházíte tisíci, použijte můj přístup. Pokud ne, použijte AddWithValue
aby byl váš kód jednoduchý a snadno udržovatelný.
Rok 2008 byl hodně dávno
Za ta léta, co jsem to napsal, se svět změnil. Existují nové druhy dat a je tu také problém, který mě nenapadl, dokud mě nedávný problém s daty nepřiměl přemýšlet o důsledcích rozšíření.
Rozšiřování a zužování, pro ty, kteří tyto pojmy neznají, jsou vlastnosti převodů datových typů. Pokud přiřadíte int k double, nedojde ke ztrátě přesnosti, protože double je "širší". Je to vždy bezpečné, takže převod je automatický. To je důvod, proč můžete přiřadit int k double, ale opačným způsobem musíte provést explicitní obsazení - double to int je zužující převod s potenciální ztrátou přesnosti.
To se může týkat řetězců:NVARCHAR je širší než VARCHAR, takže můžete přiřadit VARCHAR k NVARCHAR, ale jít opačným způsobem vyžaduje přetypování. Porovnání funguje, protože VARCHAR se implicitně rozšiřuje na NVARCHAR, ale to bude narušovat použití indexů!
Řetězce C# jsou Unicode, takže AddWithValue vytvoří parametr NVARCHAR. Na druhém konci se hodnoty sloupce VARCHAR pro srovnání rozšíří na NVARCHAR. Tím se nezastaví provádění dotazu, ale zabrání se použití indexů. To je špatné.
co s tím můžete dělat? Máte dvě možná řešení.
- Explicitně zadejte parametr. To znamená, že už žádné AddWithValue
- Změňte všechny typy sloupců řetězců na NVARCHAR.
Vykopání VARCHAR je pravděpodobně nejlepší nápad. Je to jednoduchá změna s předvídatelnými důsledky a vylepšuje váš příběh o lokalizaci. Tuto možnost však možná nemáte.
V dnešní době moc přímo ADO.NET nedělám. Linq2Sql je nyní mou oblíbenou zbraní a psaní této aktualizace mě nechalo přemýšlet, jak tento problém řeší. Mám náhlou, spalující touhu zkontrolovat svůj přístupový kód k datům pro vyhledání pomocí sloupců VARCHAR.
2019 a svět se pohnul opět
Linq2Sql není k dispozici v dotnet Core, takže jsem zjistil, že používám Dapper. Problém [N]VARCHAR je stále věc, ale už není tak daleko. Věřím, že lze také použít ADO, takže se věci v tomto ohledu uzavřely.