Co się tam dzieje?
Cytujesz listy parametrów dla kilku przeciążeń Add
. Są to wygodne metody, które odpowiadają bezpośrednio przeciążeniom konstruktorów dla SqlParameter
klasa. Zasadniczo konstruują obiekt parametru przy użyciu dowolnego konstruktora, który ma ten sam podpis, co wygodna metoda, którą wywołałeś, a następnie wywołują SqlParameterCollection.Add(SqlParameter)
tak:
SqlParameter foo = new SqlParameter(parameterName, dbType, size);
this.Add(foo);
AddWithValue
jest podobny, ale zapewnia jeszcze większą wygodę, również ustawiając wartość. W rzeczywistości został jednak wprowadzony, aby rozwiązać problem z frameworkiem. Cytując MSDN,
Przeciążenie Add
który przyjmuje astring, a obiekt został uznany za przestarzały z powodu możliwej niejednoznaczności z SqlParameterCollection.Add
przeciążenie, które przyjmuje String
i SqlDbType
wartość wyliczenia, w której przekazanie liczby całkowitej z ciągiem znaków może zostać zinterpretowane jako wartość parametru lub odpowiadający SqlDbType
wartość. Użyj AddWithValue
kiedy chcesz dodać parametr, określając jego nazwę i wartość.
Przeciążenia konstruktora dla SqlParameter
class to zwykłe udogodnienia do ustawiania właściwości instancji. Skracają kod, z marginalnym wpływem na wydajność:konstruktor może ominąć metody ustawiające i operować bezpośrednio na członkach prywatnych. Jeśli jest różnica, to nie będzie duża.
Co mam zrobić?
Zwróć uwagę na następujące informacje (z MSDN)
W przypadku parametrów dwukierunkowych i wyjściowych oraz wartości zwracanych należy ustawić wartość Size
. Nie jest to wymagane w przypadku parametrów wejściowych, a jeśli nie jest jawnie ustawione, wartość jest wywnioskowana z rzeczywistego rozmiaru określonego parametru podczas wykonywania aparametryzowanej instrukcji.
Domyślnym typem jest wejście. Jeśli jednak zezwolisz na wywnioskowanie rozmiaru w ten sposób i odtworzysz obiekt parametru w pętli (mówiłeś, że martwisz się wydajnością), wówczas rozmiar zostanie ustawiony na podstawie pierwszej wartości, a wszystkie kolejne wartości, które są dłuższe, będą obcięty. Oczywiście ma to znaczenie tylko w przypadku wartości o zmiennej długości, takich jak łańcuchy.
Jeśli wielokrotnie przekazujesz ten sam parametr logiczny w pętli, zalecam utworzenie obiektu SqlParameter poza pętlą i odpowiedniego jego rozmiaru. Przewymiarowanie varchara jest nieszkodliwe, więc jeśli jest to PITA, aby uzyskać dokładne maksimum, po prostu ustaw go na większy, niż kiedykolwiek się spodziewasz. Ponieważ przetwarzasz obiekt zamiast tworzyć nowy dla każdej iteracji, zużycie pamięci w czasie trwania pętli prawdopodobnie spadnie nawet jeśli jesteś trochę podekscytowany przewymiarowaniem.
Prawdę mówiąc, jeśli nie przetworzysz tysięcy połączeń, nic z tego nie zrobi dużej różnicy. AddWithValue
tworzy nowy obiekt, unikając problemu z rozmiarami. Jest krótki, słodki i łatwy do zrozumienia. Jeśli przejdziesz przez tysiące, skorzystaj z mojego podejścia. Jeśli nie, użyj AddWithValue
aby Twój kod był prosty i łatwy w utrzymaniu.
2008 był dawno temu
Przez lata, odkąd to napisałem, świat się zmienił. Pojawiają się nowe rodzaje randek, a także problem, który nie przyszedł mi do głowy, dopóki niedawny problem z datami nie skłonił mnie do zastanowienia się nad implikacjami poszerzenia.
Poszerzanie i zawężanie, dla osób niezaznajomionych z terminami, to cechy konwersji typu danych. Jeśli przypiszesz int do double, nie ma utraty precyzji, ponieważ double jest „szersze”. Zawsze jest to bezpieczne, więc konwersja jest automatyczna. Dlatego możesz przypisać int do double, ale idąc w drugą stronę musisz wykonać jawne rzutowanie - double do int to zawężająca konwersja z potencjalną utratą precyzji.
Może to dotyczyć łańcuchów:NVARCHAR jest szerszy niż VARCHAR, więc możesz przypisać VARCHAR do NVARCHAR, ale przejście w drugą stronę wymaga rzutowania. Porównanie działa, ponieważ VARCHAR niejawnie rozszerza się do NVARCHAR, ale to będzie zakłócać korzystanie z indeksów!
Ciągi C# są Unicode, więc AddWithValue wygeneruje parametr NVARCHAR. Z drugiej strony wartości kolumn VARCHAR rozszerzają się do NVARCHAR dla porównania. Nie zatrzymuje to wykonywania zapytania, ale uniemożliwia użycie indeksów. To jest złe.
Co możesz z tym zrobić? Masz dwa możliwe rozwiązania.
- Wyraźnie wpisz parametr. Oznacza to koniec z AddWithValue
- Zmień wszystkie typy kolumn ciągów na NVARCHAR.
Porzucenie VARCHAR jest prawdopodobnie najlepszym pomysłem. To prosta zmiana z przewidywalnymi konsekwencjami, która poprawia Twoją historię lokalizacji. Jednak możesz nie mieć tego jako opcji.
Obecnie nie robię dużo bezpośredniego ADO.NET. Linq2Sql jest teraz moją ulubioną bronią, a pisanie tej aktualizacji sprawiło, że zacząłem się zastanawiać, jak radzi sobie z tym problemem. Mam nagłe, palące pragnienie sprawdzenia mojego kodu dostępu do danych w celu wyszukania za pomocą kolumn VARCHAR.
2019 i świat ruszył znowu
Linq2Sql nie jest dostępny w dotnet Core, więc używam Dappera. Problem [N]VARCHAR nadal istnieje, ale nie jest już tak daleko pogrzebany. Uważam, że można również użyć ADO, więc w tym względzie sprawy zatoczyły koło.