Serwisanci dostępni teraz · czynne całą dobę, także w weekendy i świętaWarszawa i okolice · dojazd bezpłatny
Darmowa diagnoza laptopa
Darmowa diagnoza laptopa
Dojazd do klienta bezpłatnie
Dojazd do klienta bezpłatnie
Laptopy zastępcze bezpłatnie
Laptopy zastępcze bezpłatnie
Odbiór i zwrot sprzętu bezpłatnie
Odbiór i zwrot sprzętu bezpłatnie

SqlDataAdapter

Termin Definicja
SqlDataAdapter

SqlDataAdapter to klasa .NET pośrednicząca między poleceniami SQL a zbiorem danych aplikacji.

SqlDataAdapter jako warstwa komunikacji z bazą danych

SqlDataAdapter jest klasą platformy .NET używaną do pobierania danych z relacyjnej bazy SQL oraz przekazywania zmian z aplikacji z powrotem do bazy. Pełni rolę pośrednika między obiektem reprezentującym połączenie z bazą a obiektem DataSet lub DataTable. Dzięki temu aplikacja nie musi przez cały czas utrzymywać aktywnego połączenia podczas pracy z pobranym zestawem rekordów. Dane mogą zostać pobrane, przeanalizowane i zmodyfikowane w pamięci, a następnie zapisane przy użyciu odpowiednio skonfigurowanych poleceń.

W praktyce SqlDataAdapter korzysta z obiektu SqlConnection oraz z polecenia SqlCommand. Najczęściej ustawia się właściwość SelectCommand, która określa zapytanie odczytujące dane. Po wywołaniu metody Fill() adapter otwiera połączenie, jeżeli nie zostało otwarte wcześniej, wykonuje zapytanie, kopiuje wynik do tabeli w pamięci, a następnie może zamknąć połączenie. Takie zachowanie upraszcza kod i pozwala rozdzielić etap pobierania danych od późniejszej pracy interfejsu lub logiki aplikacji.

SqlDataAdapter jest szczególnie przydatny w klasycznym modelu ADO.NET, w którym dane są przechowywane w strukturze odłączonej od bieżącego połączenia. W DataTable zachowywane są nie tylko wartości kolumn, lecz także informacje o stanie wierszy. Można dzięki temu rozpoznać rekordy nowe, zmienione oraz usunięte. Adapter wykorzystuje te informacje podczas synchronizacji zawartości pamięci z bazą danych.

SqlDataAdapter a DataTable, DataSet i inne sposoby dostępu

Wybór SqlDataAdapter zależy od sposobu organizacji pracy z danymi. DataReader jest przeznaczony głównie do szybkiego, sekwencyjnego odczytu rekordów przy aktywnym połączeniu. Sprawdza się wtedy, gdy dane są przetwarzane w jednym kierunku i nie ma potrzeby ich edycji w pamięci. SqlDataAdapter działa inaczej: wypełnia obiekt danych, który może być używany po zakończeniu operacji z bazą. Zapewnia to większą swobodę, ale zwykle wiąże się z przechowywaniem większej ilości informacji w pamięci.

W porównaniu z ręcznym wykonywaniem osobnych poleceń INSERT, UPDATE i DELETE adapter pozwala zebrać konfigurację operacji w jednym obiekcie. Nie oznacza to jednak, że wszystkie zapytania są tworzone automatycznie. Dla prostych tabel można skorzystać z SqlCommandBuilder, który na podstawie polecenia SELECT próbuje wygenerować polecenia modyfikujące. Takie rozwiązanie wymaga jednoznacznego klucza głównego i odpowiedniej konstrukcji zapytania. Przy bardziej złożonych zapytaniach, połączeniach tabel lub niestandardowych regułach biznesowych bezpieczniej jest jawnie zdefiniować każde polecenie.

Możliwe jest także wypełnienie wielu tabel znajdujących się w jednym DataSet. Wtedy każda tabela może mieć własny adapter albo własne polecenie, a relacje między tabelami mogą zostać odwzorowane w pamięci. Takie podejście bywa wygodne w aplikacjach formularzowych i starszych rozwiązaniach biznesowych. W nowszym kodzie należy jednak rozważyć, czy pełny model odłączony jest potrzebny, ponieważ przy dużych zbiorach może zwiększać zużycie pamięci i utrudniać kontrolę nad aktualnością danych.

Ważną cechą SqlDataAdapter jest rozdzielenie zapytania od parametrów. Wartości pochodzące od użytkownika powinny być przekazywane przez SqlParameter, a nie wklejane bezpośrednio do tekstu SQL. Ogranicza to ryzyko błędnej interpretacji danych i pomaga chronić aplikację przed wstrzyknięciem poleceń SQL.

SqlDataAdapter i typowe problemy w działaniu aplikacji

Jednym z częstych problemów jest niepoprawne zarządzanie połączeniem. Jeżeli adapter otrzyma połączenie już otwarte, nie powinno się zakładać, że po zakończeniu Fill() stan połączenia będzie taki sam w każdym scenariuszu użycia. Warto jasno ustalić, która część kodu odpowiada za otwieranie i zamykanie połączenia, a obiekty takie jak SqlConnection, SqlCommand i SqlDataAdapter należy zwalniać przez konstrukcję using albo równoważny mechanizm.

Trudności pojawiają się także przy wywołaniu Update(). Sama zmiana wartości w wierszu DataTable nie zapisuje jej automatycznie w bazie. Najpierw trzeba zdefiniować InsertCommand, UpdateCommand oraz DeleteCommand, bezpośrednio albo za pomocą generatora poleceń. Trzeba również sprawdzić, czy wiersze mają poprawne statusy i czy kolumny klucza są dostępne. Brak klucza głównego, niejednoznaczne zapytanie lub niezgodność typów mogą spowodować, że adapter nie będzie potrafił ustalić, który rekord ma zostać zmieniony.

Inną przyczyną błędów jest konflikt aktualizacji. Może do niego dojść, gdy rekord został zmieniony w bazie przez inną część aplikacji pomiędzy pobraniem danych a próbą zapisu. W zależności od konfiguracji polecenia aktualizującego można porównywać wyłącznie klucz albo także wcześniejsze wartości kolumn. Drugie podejście lepiej wykrywa nadpisanie cudzej zmiany, lecz wymaga starannie przygotowanego zapytania i obsługi sytuacji, w której nie zaktualizowano żadnego wiersza.

Wydajność może pogorszyć się wtedy, gdy do DataTable pobierany jest cały zbiór danych, mimo że ekran potrzebuje tylko kilku kolumn lub bieżącej strony rekordów. Wskazane jest ograniczanie zakresu SELECT, stosowanie filtrów, wybieranie potrzebnych kolumn oraz analizowanie planu zapytania po stronie bazy. Należy też uważać na wielokrotne wywoływanie Fill(), ponieważ bez właściwego użycia może ono dopisywać kolejne dane albo odświeżać zawartość w sposób niezgodny z oczekiwaniem aplikacji.

SqlDataAdapter w praktycznym kodzie i codziennej diagnostyce

Przy projektowaniu kodu warto rozpocząć od określenia cyklu życia danych. Jeżeli dane są tylko wyświetlane, prostszy może być odczyt za pomocą DataReader. Jeżeli mają być filtrowane, edytowane w formularzu, porównywane lub przekazywane między elementami aplikacji, SqlDataAdapter i DataTable mogą zapewnić wygodniejszy model pracy. Należy przy tym kontrolować wielkość pobieranego zbioru, ponieważ wygoda danych odłączonych nie eliminuje kosztu ich przechowywania.

Zapytania powinny być parametryzowane, a nazwy tabel i kolumn najlepiej utrzymywać w sposób kontrolowany, bez składania ich z przypadkowego tekstu. Przy parametrach należy dobrać właściwy typ danych, długość oraz kierunek przekazywania. Ma to znaczenie dla poprawnej konwersji, indeksów i przewidywalnego działania zapytań. Dla wartości pustych należy świadomie rozróżniać null w kodzie od DBNull.Value używanego przez ADO.NET.

Podczas diagnozowania problemu przydatne jest sprawdzenie kolejno: tekstu zapytania, parametrów, stanu połączenia, struktury tabeli, klucza głównego oraz liczby wierszy zwróconych przez Fill(). W przypadku Update() należy dodatkowo ustalić, ile rekordów zostało oznaczonych jako zmienione oraz ile poleceń faktycznie wpłynęło na bazę. Rejestrowanie wyjątków powinno obejmować kod błędu i kontekst operacji, ale bez zapisywania haseł, pełnych danych logowania oraz poufnych wartości parametrów.

W aplikacjach wielowątkowych nie należy współdzielić bez kontroli tych samych obiektów danych pomiędzy niezależnymi operacjami. Bezpieczniejszy jest jasno określony zakres użycia oraz osobne instancje połączeń i adapterów. Pomaga to ograniczyć nieprzewidywalne zmiany, problemy z blokadami i trudne do odtworzenia rozbieżności.

SqlDataAdapter i moment zgłoszenia problemu do serwisu

Do serwisu warto zgłosić się wtedy, gdy aplikacja przestała pobierać dane po zmianie systemu, sterowników, konfiguracji połączenia lub środowiska .NET, a sam komunikat błędu nie pozwala ustalić przyczyny. Pomoc może być potrzebna również wtedy, gdy program uruchamia się poprawnie, lecz dane nie są odświeżane, zapis zmian kończy się wyjątkiem albo operacja trwa znacznie dłużej niż wcześniej. Przed przekazaniem sprzętu dobrze przygotować opis objawów, moment wystąpienia problemu oraz informację, czy błąd dotyczy jednego programu, czy całego środowiska.

W ramach wsparcia Warszawskie Pogotowie Komputerowe 24/7 może pomóc w uporządkowaniu diagnostyki komputera, sprawdzeniu środowiska uruchomieniowego i rozdzieleniu problemu aplikacyjnego od problemu systemowego. Przydatne jest przekazanie treści komunikatu, fragmentu logu pozbawionego danych poufnych oraz informacji o ostatnich zmianach. Nie należy udostępniać haseł do bazy ani kopiować produkcyjnych danych bez odpowiedniego zabezpieczenia.

Warto pamiętać, że błąd SqlDataAdapter nie zawsze oznacza uszkodzenie sprzętu. Przyczyną może być brak dostępu do bazy, niezgodność wersji bibliotek, błędny parametr, zmiana schematu tabeli, problem z uprawnieniami albo nieobsłużony konflikt aktualizacji. Metodyczne sprawdzenie tych obszarów pozwala szybciej ustalić właściwy kierunek naprawy i ograniczyć ryzyko przypadkowej utraty danych.

+48 22 100 48 29Zadzwoń teraz · serwisant w 1 godzinę