2011-01-07 9 views
35

Jest powiązany z tym pytanie:Kiedy należy używać "SqlDbType" i "size" podczas dodawania parametrów SqlCommand?

What's the best method to pass parameters to SQLCommand?

Ale ja chce wiedzieć jakie są różnice i czy są jakieś problemy z różnych sposobów.

Zwykle używam strukturę coś takiego:

using (SqlConnection conn = new SqlConnection(connectionString)) 
using (SqlCommand cmd = new SqlCommand(SQL, conn)) 
{ 
    cmd.CommandType = CommandType.Text; 
    cmd.CommandTimeout = Settings.Default.reportTimeout; 
    cmd.Parameters.Add("type", SqlDbType.VarChar, 4).Value = type; 

    cmd.Connection.Open(); 

    using (SqlDataAdapter adapter = new SqlDataAdapter(cmd)) 
    { 
     adapter.Fill(ds); 
    } 
     //use data      
} 

Obecnie istnieje kilka sposobów dodawania CMD parametry i zastanawiam się, który jest najlepszy:

cmd.Parameters.Add("@Name", SqlDbType.VarChar, 20).Value = "Bob"; 
cmd.Parameters.Add("@Name", SqlDbType.VarChar).Value = "Bob"; 
cmd.Parameters.Add("@Name").Value = "Bob"; 
cmd.Parameters.AddWithValue("@Name", "Bob"); 

uwzględniając długość pole przy przechodzeniu przez varchary zakładam, że nie jest lepsze, ponieważ jest to magiczna wartość, którą można później zmienić w bazie danych. Czy to jest poprawne? Czy to powoduje problem przechodzący varchar w ten sposób (wydajność lub inne), domyślam się, że domyślnie varchar (max) lub ekwiwalent bazy danych. Jestem całkiem zadowolony, że to zadziała.

Częścią, która mnie bardziej niepokoi jest utrata wyliczenia SqlDbType, jeśli korzystam z trzeciej lub czwartej opcji wymienionej powyżej, w ogóle nie dostarczam typu. Czy są przypadki, w których to nie zadziała Mogę sobie wyobrazić problemy z niepoprawnym rzutowaniem varchar na char lub vice versa lub z dziesiętną na pieniądze ...

Pod względem bazy danych typ pola, który chciałbym powiedzieć, to znacznie mniej prawdopodobne, aby zmienić niż długość, więc czy warto go zatrzymać?

+3

Nie odpowiadając na twoje pytanie, wiesz, że nie musisz otwierać połączenia przed wywołaniem 'SqlDataAdapter.Fill()', i że nie ma takiej możliwości? –

+0

@Rowland dobry punkt. Wiedziałem, że chociaż było to niedopatrzenie w moim kodzie. Myślę, że wziąłem oryginalny blok kodu skądś, że używałem SqlDataReader, a nie adaptera (musisz otworzyć połączenie dla tego prawa?). To właśnie dostajesz za niegrzeczne kopiowanie/programowanie :-). Naprawiono teraz mój kod. – PeteT

+0

po prostu pomyślałem, że wspomnę o tym, ponieważ jest to jedna z tych "nieznanych wskazówek, o których ludzie mogą nie wiedzieć" –

Odpowiedz

49

Z mojego doświadczenia, chciałbym się upewnić, to czynię:

  • upewnić się, że to ty, który określa typ danych parametru. ADO.NET robi dobrej pracy w zgadywanie, ale w niektórych przypadkach może to być strasznie off - więc chciałbym uniknąć tej metody:

    cmd.Parameters.Add("@Name").Value = "Bob"; 
    cmd.Parameters.AddWithValue("@Name", "Bob"); 
    

    Letting ADO.NET odgadnąć typ parametru przez wartość przekazywana jest podchwytliwe, a jeśli z jakiegokolwiek powodu jest wyłączone, są to naprawdę podstępne błędy do śledzenia i znajdowania! Wyobraź sobie, co dzieje się, gdy przechodzisz w DBNull.Value - jaki typ danych powinien wybrać dla tego ADO.NET?

    Po prostu powiedz wprost - powiedz jaki typ chcesz!

  • jeśli używasz parametrów ciągów, upewnij się jednoznacznie określić długość - więc chciałbym uniknąć tej metody, za:

    cmd.Parameters.Add("@Name", SqlDbType.VarChar).Value = "Bob"; 
    

    Jeśli nie zapewniają długość Ado. NET może domyślnie ustawić dowolną dowolną wartość lub długość łańcucha przekazaną jako wartość lub coś innego - nigdy nie jesteś całkiem pewien. A jeśli twoja długość nie pasuje do tego, czego rzeczywiście oczekuje zapisany proces, możesz zobaczyć konwersję i inne nieprzyjemne niespodzianki. Jeśli więc zdefiniujesz łańcuch, zdefiniuj jego długość!

Więc w twoim przypadku, jedynym podejściem, które naprawdę działa dla mnie jest to jeden tutaj:

cmd.Parameters.Add("@Name", SqlDbType.VarChar, 20).Value = "Bob"; 

ponieważ a) określa typ danych do użycia jawnie, oraz b) określa długość ciąg jawnie.

+0

Jeśli używasz procedury składowanej, nie możesz po prostu pobrać parametru z metadanych dostarczonych przez SqlCommandBuilder.DeriveParameters (cmd)? – devinbost

+0

Czy długość powinna być wartością podstawowej definicji parametru? A jeśli tak, to czy nie narusza to DRY? – tbone

4

Po dodaniu typu Twoje zapytania mogą zwiększyć wydajność, korzystając z planu zapytań w pamięci podręcznej.

Oto cytat z MSDN:

Parametryzowane polecenia może również poprawić wydajność wykonywania zapytań, ponieważ pomagają serwer bazy danych dokładnie dopasować polecenia przychodzące z właściwego planu kwerend pamięci podręcznej.

Więcej informacji w Execution Plan Caching and Reuse.

+0

Wszystkie opcje Pete'a są parametryzowane, więc zdziwiłbym się, gdyby dodanie parametrów w różny sposób wpłynęło na wydajność - z pewnością nie jest to wyraźnie wspomniane w artykule, z którym się łączyłeś. –

+4

Nie zgadzam się. To, co opisuje artykuł, polega na tym, że definiując parametr tak dokładnie, jak to możliwe, jest bardziej prawdopodobne, że zostanie użyty buforowany plan zapytania, a następnie z wyższą wydajnością. W podrozdziale "Prosta parametryzacja" jest napisane: W SQL Server używanie parametrów lub znaczników parametrów w instrukcjach Transact-SQL zwiększa zdolność mechanizmu relacyjnego do dopasowania nowych instrukcji SQL do istniejących, wcześniej skompilowanych planów wykonania. – StefanE

Powiązane problemy