Doug RothausMike Pizzo
Microsoft Corporation
Streszczenie: W artykule tym omówiono architekturę dostępu do danych zapewnianą przez ADO.NET i zamieszczono odpowiedzi na najczęściej zadawane pytania, jakie nurtują programistów znających wcześniejszą technologię ADO.Długość dokumentu po wydrukowaniu — około 14 stron.
WprowadzenieOpisTechnologia ADOADO.NET — jawne działanie i specjalizacjaTypy danychPodsumowanieNajczęściej zadawane pytania Co stało się z obiektem Recordset? Co stało się z kursorami? Jak wypełnić obiekt DataSet danymi, jeśli jest on odłączony od źródła danych? Jak wprowadzone w obiekcie DataSet zmiany przenieść z powrotem do bazy danych? Czy w ADO.NET istnieje metoda korzystania z danych XML podobna do adPersistXml? W jaki sposób w .NET Framework używać istniejących komponentów COM, które wykorzystują ADO do pozyskiwania i aktualizowania danych?
Wraz z platformą .NET Framework, Microsoft wprowadził ADO.NET — rozwinięcie architektury dostępu do danych, zapewnianej przez obiekty Microsoft® ActiveX® Data Objects (ADO). Programiści piszący komponenty COM nie powinni rezygnować z korzystania z ADO na rzecz ADO.NET. ADO.NET jest przeznaczone dla programistów tworzących aplikacje na platformę .NET i ma zapewnić dostęp do relacyjnych źródeł danych, do XML i do danych aplikacji. ADO.NET ułatwia wiele zadań programistycznych, takich jak tworzenie klientów baz danych czy tworzenie obiektów biznesowych warstwy pośredniczącej, wykorzystywanych przez aplikacje, narzędzia, języki i przeglądarki internetowe.
Opracowywana z myślą o programistach ADO biblioteka ADO.NET jest w dużym stopniu podobna do ADO, jednak w jej projekcie znalazło się także kilka nowych pomysłów. Dokument ten zawiera odpowiedzi na najczęściej zadawane pytania, stawiane przez programistów ADO stykających się z technologią ADO.NET po raz pierwszy.
Technologia ADO od chwili wprowadzenia zapewniała programistom tworzącym obiekty COM wydajny i rozbudowany interfejs do pracy z danymi. Ponieważ obiekty ADO można wywołać z dowolnego języka programowania — z Microsoft Visual Basic® 6.0, Microsoft Visual C++®, a także z wielu interfejsów skryptowych — technologia ta jest szeroko wykorzystywana jako interfejs umożliwiający dostęp do wielu różnych magazynów danych.
ADO.NET to nowa wersja biblioteki, rozwijająca możliwości ADO. Zapewnia lepszą współpracę z innymi platformami i skalowalny dostęp do danych. Utworzenie w ADO.NET nowych zestawów interfejsów API dostępu do danych (zamiast zwykłego przeniesienia ADO na platformę .NET Framework) zaowocowało następującymi zaletami:
Lepsza integracja z XML. Po zaprojektowaniu i wprowadzeniu technologii ADO, w projektowaniu aplikacji coraz bardziej znaczącą rolę zaczął odgrywać język XML. Projekt ADO.NET od samego początku zakładał ścisłą integrację z XML i pełne wykorzystanie możliwości tego języka. Oprócz przechowywania i ładowania danych oraz ich struktury relacyjnej w postaci XML, ADO.NET wykorzystuje XML także do przekazywania danych pomiędzy warstwami aplikacji oraz klientami. Wykorzystywana w ADO.NET reprezentacja danych w postaci XML zapewnia wygodną metodę transmisji danych w dowolnej sieci, włącznie z sieciami o bardzo restrykcyjnych zasadach bezpieczeństwa. ADO.NET wykorzystuje także narzędzia XML do przeprowadzania walidacji danych, wykonywania zapytań hierarchicznych i transformacji danych relacyjnych.
Integracja z platformą .NET Framework. Konstrukcje ADO — takie jak obiekty Recordset — nie przypominają znanych konstrukcji programistycznych. Ich modele obiektowe przypominają raczej strukturę baz danych. Na przykład działanie kursorów stosowanych do wybierania i pobierania danych jest zupełnie odmienne od działania innych struktur danych, takich jak tablice i kolekcje. W ADO.NET dane załadowane do pamięci operacyjnej mogą zostać udostępnione jako zwykłe struktury środowiska .NET Framework (na przykład tablice i kolekcje), co zapewnia spójne metody dostępu do danych relacyjnych.
Poprawiona obsługa danych w trybie offline. Obiekt Recordset w ADO zapewnia bardzo ograniczoną obsługę dostępu do danych w trybie offline. W ADO.NET wprowadzono nowy obiekt o nazwie DataSet, który działa jak standardowa, znajdująca się w pamięci relacyjna reprezentacja danych. Ponieważ obiekt DataSet z założenia nie posiada stałego połączenia z bazą danych, doskonale nadaje się do pakowania, wymiany, buforowania, przechowywania i ładowania danych.
Jawna kontrola sposobu dostępu do danych. ADO charakteryzuje się niejawnym definiowaniem zachowań, co nie zawsze jest potrzebne w aplikacjach, dlatego może to ograniczać ich wydajność. ADO.NET zapewnia dobrze zdefiniowane komponenty o dobrze wyodrębnionej funkcjonalności, cechujące się przewidywalnym zachowaniem, wydajnością i semantyką, które umożliwiają realizację często spotykanych scenariuszy w wysoce zoptymalizowany sposób.
Poprawiona obsługa czasu projektowania. ADO pozyskuje informacje na temat danych niejawnie w czasie działania, na podstawie metadanych, których uzyskanie jest często kosztowne. ADO.NET wykorzystuje natomiast metadane znane już w czasie projektowania, co pozwala na przyspieszenie pracy aplikacji i uzyskanie bardziej spójnego i konsekwentnego zachowania aplikacji w czasie jej działania.
Aby lepiej zrozumieć sposób działania i projekt biblioteki ADO.NET, dobrze jest najpierw przyjrzeć się najważniejszym cechom biblioteki ADO.
W bibliotece ADO do obsługi wszystkich sposobów dostępu do danych wykorzystywany jest jeden obiekt — Recordset. Obiekt Recordset wykorzystywany jest do pracy z jednokierunkowymi strumieniami wyników z bazy danych, do przeglądania danych znajdujących się na serwerze lub do przeglądania zbuforowanych wyników. Zmiany wprowadzone w danych można przenieść do bazy danych natychmiast lub zastosować aktualizowanie wsadowe z wykorzystaniem optymistycznych operacji wyszukiwania i uaktualniania danych. Pożądaną funkcjonalność obiektu Recordset określa się podczas tworzenia jego instancji, a działanie otrzymanego obiektu Recordset może być bardzo różne w zależności od wybranych właściwości.
Ze względu na stosowanie w ADO tylko jednego obiektu, który może działać na wiele różnych sposobów, model obiektowy tworzonych aplikacji pozostaje bardzo prosty. Trudno jest jednak tworzyć zoptymalizowany kod o przewidywalnym działaniu, ponieważ sposób działania, wydajność i semantyka tego pojedynczego obiektu może się znacznie różnić w zależności od sposobu jego wygenerowania oraz tego, do jakich danych umożliwia dostęp. Problem ten jest szczególnie widoczny w komponentach takich jak kontrolka tabeli danych w przypadku dostępu do danych, które nie zostały wygenerowane przez ten komponent oraz dla których komponent nie ma możliwości określenia ani sposobu działania, ani funkcjonalności.
Projektując ADO.NET uwzględniono różnorodność problemów, jakie napotykają programiści podczas dostępu do danych i pracy z danymi. Zamiast tworzyć jeden obiekt, który mógłby wykonywać wszystkie zadania, w bibliotece ADO.NET funkcjonalność ta została podzielona na kilka osobnych, specjalizowanych obiektów, które są zoptymalizowane i pozwalają programiście zrealizować poszczególne zadania.
Funkcjonalność obiektu Recordset z biblioteki ADO została podzielona w ADO.NET na następujące specjalizowane obiekty: DataReader — zapewniający szybki, jednokierunkowy dostęp do wyników zapytania w trybie tylko do odczytu, DataSet — zapewniający relacyjną reprezentację danych w pamięci operacyjnej, DataAdapter — stanowiący most pomiędzy obiektem DataSet a źródłem danych. Funkcjonalność obiektu Command w bibliotece ADO.NET także została jawnie rozdzielona na różne funkcje — do obsługi poleceń, które nie zwracają żadnych wierszy danych, przeznaczona jest metoda ExecuteNonQuery, natomiast metoda ExecuteScalar umożliwia wykonywanie zapytań, które zwracają pojedynczą wartość, a nie cały zbiór wierszy.
Aby lepiej zrozumieć podział funkcjonalności biblioteki ADO.NET na zoptymalizowane obiekty przeznaczone do określonych celów, przyjrzyjmy się następującym zadaniom, często wykonywanym podczas pracy z danymi:
Aplikacje, a w szczególności aplikacje warstwy pośredniczącej, często przetwarzają serie wyników otrzymanych z bazy danych, nie angażując przy tym użytkownika, nie uaktualniając danych ani nie cofając się w otrzymanym zbiorze wyników. W bibliotece ADO zadanie to jest wykonywane za pomocą obiektu Recordset z jednokierunkowym kursorem danych oraz z ustawioną flagą sygnalizującą, że wykonywane mogą być tylko operacje odczytu. Natomiast w ADO.NET ten typ operacji na danych przeprowadzany jest przy użyciu zoptymalizowanego obiektu DataReader, zapewniającego obsługę niebuforowanego, jednokierunkowego strumienia umożliwiającego wyłącznie odczyt danych. Jest to najbardziej wydajny mechanizm pobierania wyników z bazy danych. Osiągnięcie tak dużej wydajności było możliwe właśnie dlatego, że obiekt DataReader został zaprojektowany wyłącznie do realizacji operacji jednego typu — nie musi obsługiwać scenariuszy, w których dane są aktualizowane w źródle danych lub buforowane lokalnie, jak robi to obiekt Recordset z biblioteki ADO.
Często konieczne jest pobranie z bazy danych tylko jednej wartości (na przykład stanu konta). W ADO zadanie to wygląda następująco: utworzenie obiektu Recordset, przejrzenie wyników i wybranie pojedynczej wartości, zamknięcie obiektu Recordset. W ADO.NET obiekt Command pozwala na wykonanie tego zadania za pomocą metody ExecuteScalar, zwracającej pojedynczą wartość z bazy danych bez konieczności używania dodatkowego obiektu, który tymczasowo przechowuje wyniki.
Dane często udostępniane są w sposób umożliwiający użytkownikowi „luźne” ich przeglądanie, bez rezerwowania i blokowania zasobów na serwerze. Przykładem takiego zastosowania jest powiązanie kontrolki z danymi lub łączenie danych z wielu źródeł danych i plików XML. Obiekt Recordset biblioteki ADO w pewnym stopniu umożliwiał realizację takich sposobów dostępu za pomocą kursora działającego po stronie klienta. Natomiast w bibliotece ADO.NET istnieje obiekt specjalnie przeznaczony do tego typu zastosowań. Jest to obiekt DataSet.
Obiekt DataSet zapewnia standardową, działającą w trybie offline reprezentację danych pochodzących z wielu różnych źródeł. Ponieważ obiekt DataSet jest całkowicie niezależny od źródła danych, zapewnia taką samą wydajność i semantykę bez względu na to, czy dane są pobierane z bazy danych, z pliku, czy też są generowane przez aplikację. Pojedynczy obiekt DataSet może zawierać tabele wypełnione danymi z kilku różnych baz danych lub innych źródeł danych niebędących bazami. Dla klienta korzystającego z obiektu DataSet, wszystkie dane dostępne są w taki sam sposób i mogą być tak samo przetwarzane. Wewnątrz obiektu DataSet można zdefiniować relacje pomiędzy tabelą pobraną z jednej bazy danych (na przykład „Klienci”) a tabelą wypełnioną danymi pochodzącymi z zupełnie innej bazy danych (na przykład „Zamówienia”), a tę z kolei tabelę połączyć relacją z trzecią tabelą (na przykład „SzczegółyZamówienia”), zawierającą dane pobrane z pliku XML. Relacyjne możliwości obiektu DataSet dają dużą przewagę tego obiektu nad obiektem Recordset, udostępniającym wyniki z wielu tabel albo jako jeden połączony zbiór danych, albo w postaci kilku odrębnych zbiorów danych, które programista musi sam obsłużyć i połączyć relacjami. Chociaż obiekt Recordset zapewnia możliwość zwracania i przeglądania wyników w sposób hierarchiczny (przy użyciu dostawcy MSDataShape), obiekt DataSet zapewnia dużo większą elastyczność działań na powiązanych ze sobą zbiorach danych. Obiekt DataSet umożliwia także przekazywanie wyników w formacie XML do i ze zdalnego klienta lub serwera z zastosowaniem schematu XML zdefiniowanego przy użyciu języka XSD (XML Schema Definition).
Na podstawie opinii klientów oraz najczęstszych przypadków zastosowań wiadomo, że w większości przypadków (poza narzędziami ad hoc i uniwersalnymi komponentami dostępu do danych) programista zna pewne właściwości przetwarzanych danych już na etapie projektowania aplikacji. Technologie takie jak ADO pobierają tego typu informacje w czasie działania aplikacji. Przy projektowaniu większości aplikacji warstwy pośredniczącej, programista już w czasie jej opracowywania zna typ bazy danych i wie, jakie zapytania będą wykonywane oraz w jaki sposób będą zwracane wyniki. ADO.NET umożliwia wykorzystanie tej wiedzy w czasie projektowania, co pozwala na budowanie bardziej wydajnych i lepiej działających aplikacji.
Na przykład podczas wykonywania wsadowego uaktualniania bazy danych, obiekt Recordset biblioteki ADO przekazuje zmiany do bazy danych, wykonując dla każdego zmodyfikowanego wiersza polecenie INSERT, UPDATE lub DELETE. ADO generuje te polecenia niejawnie, w czasie działania aplikacji, na podstawie metadanych, których uzyskanie jest często bardzo kosztowne. Natomiast ADO.NET pozwala na jawne podanie poleceń INSERT, UPDATE i DELETE (a także niestandardowej logiki biznesowej, na przykład procedury przechowywanej) wykorzystywanych przez obiekt DataAdapter podczas zapisywan...
SacrA