| Termin | Definicja |
|---|---|
| SqlCommand | SqlCommand to klasa .NET reprezentująca polecenie SQL wykonywane na aktywnym połączeniu z bazą. SqlCommand jako obiekt polecenia w aplikacji .NETSqlCommand to element biblioteki ADO.NET służący do przekazania instrukcji SQL do relacyjnej bazy danych. W praktyce obiekt ten opisuje operację, która ma zostać wykonana za pośrednictwem aktywnego połączenia reprezentowanego najczęściej przez SqlConnection. Samo utworzenie instancji SqlCommand nie uruchamia jeszcze zapytania. Najpierw trzeba przygotować tekst instrukcji, wskazać połączenie oraz dobrać metodę wykonania odpowiednią do rodzaju oczekiwanego wyniku. Warto rozdzielić trzy pojęcia: połączenie, polecenie i rezultat. SqlConnection odpowiada za kanał komunikacji z bazą, SqlCommand przechowuje zamiar wykonania określonej operacji, a wynik może zostać zwrócony jako pojedyncza wartość, zestaw wierszy albo informacja o liczbie zmodyfikowanych rekordów. Taki podział ułatwia czytanie kodu i pozwala kontrolować cykl życia zasobów. Polecenie może zawierać zapytanie odczytujące dane, instrukcję dodającą lub zmieniającą rekordy, polecenie usuwające dane, a także wywołanie procedury zapisanej po stronie bazy. W nowoczesnym kodzie zaleca się używanie asynchronicznych metod SqlCommand, jeżeli operacja może trwać dłużej niż chwilę albo jest wykonywana w aplikacji obsługującej wielu użytkowników. Metody takie jak ExecuteReaderAsync, ExecuteScalarAsync i ExecuteNonQueryAsync pozwalają nie blokować wątku podczas oczekiwania na odpowiedź. Nie zmienia to znaczenia samego polecenia, lecz wpływa na sposób zarządzania pracą aplikacji. SqlCommand, ExecuteReader i porównanie sposobów wykonywania SQLDobór metody wykonania powinien wynikać z rodzaju rezultatu. ExecuteNonQuery stosuje się wtedy, gdy najważniejszym skutkiem jest zmiana stanu danych, na przykład dodanie rekordu, aktualizacja wybranych pól albo usunięcie wierszy. Metoda zwraca liczbę rekordów objętych operacją, co może pomóc w sprawdzeniu, czy warunek zapytania zadziałał zgodnie z założeniami. Przy instrukcjach, których skutkiem nie jest modyfikacja danych, zwracana wartość bywa zależna od sterownika i konkretnego polecenia. ExecuteScalar jest przydatne, gdy potrzebna jest jedna wartość z pierwszej kolumny pierwszego zwróconego wiersza. Ten wariant pasuje między innymi do pobierania identyfikatora utworzonego rekordu, odczytu wyniku funkcji agregującej albo sprawdzenia pojedynczego parametru. Gdy potrzebny jest pełny zestaw wyników, używa się ExecuteReader. Zwrócony czytnik umożliwia przechodzenie po rekordach i odczytywanie kolumn bez konieczności natychmiastowego kopiowania całego rezultatu do pamięci. SqlCommand może także korzystać z właściwości CommandType. Dla zwykłego tekstu SQL używa się wartości Text, natomiast przy wywoływaniu procedury zapisanej można wskazać StoredProcedure. Istnieje również wariant związany z nazwą polecenia systemowego, jednak jego zastosowanie powinno być świadome i zgodne z dokumentacją używanego dostawcy danych. Pomieszanie typu polecenia z jego treścią często prowadzi do błędów trudnych do rozpoznania na podstawie samego komunikatu. W większych operacjach można powiązać SqlCommand z transakcją. Wtedy kilka poleceń wykonuje się w ramach wspólnego zakresu, który może zostać zatwierdzony albo wycofany. Pozwala to zachować spójność, gdy na przykład zmiana jednego rekordu musi być połączona z aktualizacją danych w innej tabeli. Transakcja nie powinna obejmować niepotrzebnie długich fragmentów pracy, ponieważ utrzymywanie blokad może ograniczać dostęp innych operacji do tych samych danych. SqlCommand i typowe problemy w codziennym kodzieJednym z najczęstszych problemów jest budowanie tekstu zapytania przez łączenie go z wartościami pochodzącymi od użytkownika. Taki sposób może otwierać drogę do wstrzyknięcia SQL, a dodatkowo powodować błędy związane z formatem dat, separatorem dziesiętnym lub znakami specjalnymi. Właściwym rozwiązaniem jest używanie parametrów. Parametr powinien mieć nazwę występującą w treści zapytania, określony typ oraz wartość przekazaną niezależnie od tekstu instrukcji. Parametry zwiększają bezpieczeństwo, ale także ułatwiają ponowne wykorzystanie planu wykonania po stronie bazy. Należy jednak uważać na różnice między wartością pustą a NULL. W kodzie .NET wartość odpowiadająca SQL-owemu NULL powinna być przekazana w formie rozpoznawanej przez dostawcę danych, a nie jako zwykły pusty tekst. Pomylenie tych pojęć może sprawić, że warunek wyszukiwania nie zwróci oczekiwanych rekordów. Innym źródłem usterek jest nieprawidłowe zarządzanie zasobami. SqlCommand, SqlConnection i SqlDataReader powinny być zamykane po zakończeniu pracy, także wtedy, gdy wystąpi wyjątek. Konstrukcja using albo jej asynchroniczny odpowiednik ogranicza ryzyko pozostawienia otwartych uchwytów. W aplikacjach korzystających z puli połączeń brak zwolnienia zasobu może po pewnym czasie doprowadzić do oczekiwania na dostęp do kolejnego połączenia. Warto sprawdzać również zgodność typów i rozmiarów parametrów. Automatyczne wywnioskowanie typu na podstawie wartości nie zawsze odpowiada typowi kolumny. Dotyczy to szczególnie krótkich i długich tekstów, wartości liczbowych, dat oraz wartości logicznych. Jawne określenie typu może poprawić przewidywalność działania i ograniczyć niepotrzebne konwersje. Przy diagnostyce należy odróżnić błąd składni SQL, brak uprawnień, zerwane połączenie, przekroczenie czasu oczekiwania oraz konflikt transakcji, ponieważ każda z tych sytuacji wymaga innego działania. SqlCommand w praktyce: parametry, czas oczekiwania i diagnostykaPrzy projektowaniu polecenia warto ustalić jego zakres jeszcze przed zapisaniem kodu. Należy określić, jakie kolumny są potrzebne, jakie warunki ograniczają wynik oraz czy sortowanie i stronicowanie odbywają się po stronie bazy. Pobieranie wyłącznie wymaganych danych zwykle zmniejsza ilość przesyłanych informacji i ułatwia kontrolę nad działaniem aplikacji. W przypadku zapytań zmieniających dane powinno się rozważyć, czy warunek obejmuje dokładnie te rekordy, które mają zostać zmodyfikowane. Właściwość CommandTimeout określa, jak długo polecenie może oczekiwać na zakończenie, zanim zostanie zgłoszony błąd przekroczenia czasu. Zwiększenie tej wartości nie jest uniwersalnym rozwiązaniem problemu. Jeżeli zapytanie działa zbyt wolno, lepiej najpierw sprawdzić plan wykonania, indeksy, zakres danych i blokady. Zbyt długi limit może jedynie opóźnić ujawnienie problemu oraz zwiększyć liczbę oczekujących operacji. Przy testowaniu SqlCommand przydatne jest rejestrowanie rodzaju operacji, nazwy modułu, czasu wykonania oraz ogólnych informacji o parametrach, bez zapisywania danych wrażliwych. Komunikaty diagnostyczne powinny pozwalać ustalić, w którym miejscu aplikacji wystąpiła usterka. Nie należy bez potrzeby ujawniać pełnego tekstu zapytania ani wartości parametrów w logach dostępnych dla osób nieuprawnionych. Dobrą praktyką jest także testowanie zapytań dla pustego wyniku, pojedynczego rekordu i większego zestawu danych. Jeżeli SqlCommand wywołuje procedurę zapisaną, trzeba zwrócić uwagę na parametry wejściowe, wyjściowe oraz wartość zwracaną. Ich nazwy i typy muszą odpowiadać definicji po stronie bazy. Przy operacjach wymagających zwrócenia nowego identyfikatora należy sprawdzić, czy wybrany sposób odczytu pasuje do mechanizmu użytego w samej instrukcji. Pozwala to uniknąć sytuacji, w której polecenie wykonuje się poprawnie, lecz aplikacja interpretuje rezultat w niewłaściwy sposób. SqlCommand a moment zgłoszenia problemu do serwisu komputerowegoProblemy z SqlCommand nie zawsze wynikają z błędu w jednej linijce programu. Przyczyną może być uszkodzona instalacja środowiska, niewłaściwa konfiguracja sterownika, nieprawidłowa komunikacja z bazą, błędy systemu plików albo niestabilna praca komputera. Jeżeli aplikacja zaczyna zawieszać się podczas wykonywania zapytań, połączenia są niespodziewanie zrywane, system zgłasza błędy urządzeń lub problem pojawia się także w innych programach, potrzebna może być szersza diagnostyka komputera. Przed przekazaniem sprzętu do sprawdzenia warto zapisać treść komunikatu, moment wystąpienia problemu, nazwę używanej aplikacji oraz informację, czy błąd powtarza się przy każdym zapytaniu, czy tylko przy określonych danych. Przydatna jest również kopia zapasowa ważnych plików i konfiguracji, o ile komputer nadal pozwala na bezpieczne wykonanie takiej operacji. Nie powinno się usuwać logów ani zmieniać ustawień bazy bez zachowania informacji o stanie początkowym, ponieważ może to utrudnić rozpoznanie przyczyny. W sprawach dotyczących komputera używanego do pracy z bazami danych można skorzystać z pomocy firmy Warszawskie Pogotowie Komputerowe 24/7. W ramach zgłoszenia można opisać objawy związane z SqlCommand, sposób uruchamiania aplikacji oraz komunikaty pojawiające się podczas pracy, aby ułatwić dobór dalszych czynności diagnostycznych. Takie podejście pozwala oddzielić problem samego kodu od usterek systemu, sterowników lub podzespołów komputera. |