Udostępnij za pomocą


Konfigurowanie ustawień na poziomie połączenia i poleceń warstwy dostępu do danych (C#)

Autor : Scott Mitchell

Pobierz plik PDF

Klasy TableAdapters w typowym zestawie danych automatycznie zajmują się nawiązywaniem połączenia z bazą danych, wydawaniem poleceń i wypełnianiem tabeli DataTable z wynikami. Istnieją jednak sytuacje, w których chcemy samodzielnie dbać o te szczegóły, a w tym samouczku dowiesz się, jak uzyskać dostęp do ustawień połączenia z bazą danych i na poziomie poleceń w tabeli TableAdapter.

Wprowadzenie

W całej serii samouczków użyliśmy typów zestawów danych w celu zaimplementowania warstwy dostępu do danych i obiektów biznesowych naszej architektury warstwowej. Zgodnie z opisem w pierwszym samouczku, DataTables typu Typed DataSet służą jako repozytoria danych, natomiast TableAdapters działają jako osłony do komunikowania się z bazą danych w celu pobrania i zmodyfikowania danych źródłowych. TableAdapters hermetyzują złożoność związaną z pracą z bazą danych i chronią nas przed koniecznością pisania kodu w celu nawiązania połączenia z bazą danych, wykonania polecenia lub umieszczenia wyników w DataTable.

Czasami jednak musimy zakopać się w głębi tabeli TableAdapter i pisać kod, który działa bezpośrednio z obiektami ADO.NET. Na przykład w samouczku opakowującym modyfikacje bazy danych w ramach transakcji dodaliśmy metody do klasy TableAdapter na potrzeby rozpoczynania, zatwierdzania i wycofywania transakcji ADO.NET. Te metody używały wewnętrznego, ręcznie utworzonego SqlTransaction obiektu, który został przypisany do obiektów TableAdapter SqlCommand.

W tym samouczku sprawdzimy, jak uzyskać dostęp do ustawień połączenia z bazą danych i na poziomie polecenia w narzędziu TableAdapter. W szczególności dodamy do programu ProductsTableAdapter funkcje, które umożliwiają dostęp do podstawowych parametrów połączenia i ustawień limitu czasu polecenia.

Praca z danymi przy użyciu ADO.NET

Program Microsoft .NET Framework zawiera mnóstwo klas zaprojektowanych specjalnie do pracy z danymi. Te klasy, znajdujące się w System.Data przestrzeni nazw, są określane jako klasy ADO.NET . Niektóre klasy w ramach parasola ADO.NET są powiązane z określonym dostawcą danych. Dostawca danych można traktować jako kanał komunikacyjny, który umożliwia przepływ informacji między klasami ADO.NET a bazowym magazynem danych. Istnieją uogólnione dostawcy, tacy jak OleDb i ODBC, a także dostawcy specjalnie zaprojektowani dla określonego systemu bazy danych. Na przykład, chociaż istnieje możliwość nawiązania połączenia z bazą danych programu Microsoft SQL Server przy użyciu dostawcy OleDb, dostawca SqlClient jest o wiele bardziej wydajny, ponieważ został zaprojektowany i zoptymalizowany specjalnie dla programu SQL Server.

Podczas programowego uzyskiwania dostępu do danych często używany jest następujący wzorzec:

  • Ustanów połączenie z bazą danych.
  • Wydaj polecenie.
  • W przypadku SELECT zapytań należy pracować z wynikowymi rekordami.

Istnieją oddzielne klasy ADO.NET do wykonywania każdego z tych kroków. Aby nawiązać połączenie z bazą danych przy użyciu dostawcy SqlClient, na przykład użyj SqlConnection klasy . Aby wydać polecenie INSERT, , UPDATEDELETElub SELECT do bazy danych, użyj SqlCommand klasy .

Z wyjątkiem samouczka oprawiania modyfikacji bazy danych w transakcję, nie musieliśmy samodzielnie pisać żadnego kodu niskiego poziomu ADO.NET, ponieważ automatycznie wygenerowany kod TableAdapters zawiera funkcje potrzebne do nawiązania połączenia z bazą danych, wydawania poleceń, pobierania danych i przekształcania tych danych w tabele DataTables. Może jednak wystąpić potrzeba dostosowania tych ustawień niskiego poziomu. W następnych kilku krokach sprawdzimy, jak wykorzystać obiekty ADO.NET używane wewnętrznie przez klasy TableAdapters.

Krok 1. Badanie właściwości połączenia

Każda klasa TableAdapter posiada właściwość Connection, która określa informacje o połączeniu z bazą danych. Typ danych i wartość ConnectionString tej właściwości są określane przez wybory dokonane w kreatorze konfiguracji TableAdapter. Pamiętaj, że po pierwszym dodaniu elementu TableAdapter do typowego zestawu danych ten kreator prosi nas o źródło bazy danych (zobacz Rysunek 1). Lista rozwijana w tym pierwszym kroku zawiera te bazy danych określone w pliku konfiguracji, a także wszystkie inne bazy danych w połączeniach danych Eksploratora serwera. Jeśli baza danych, której chcemy użyć, nie istnieje na liście rozwijanej, można określić nowe połączenie z bazą danych, klikając przycisk Nowe połączenie i podając wymagane informacje o połączeniu.

Pierwszy krok Kreatora konfiguracji TableAdapter

Rysunek 1. Pierwszy krok Kreatora konfiguracji TableAdapter (Kliknij, aby wyświetlić obraz pełnowymiarowy)

Poświęćmy chwilę na sprawdzenie kodu właściwości TableAdaptera.Connection Jak wspomniano w samouczku Tworzenie warstwy dostępu do danych , możemy wyświetlić automatycznie wygenerowany kod TableAdapter, przechodząc do okna Widok klas, przechodząc do szczegółów odpowiedniej klasy, a następnie dwukrotnie klikając nazwę elementu członkowskiego.

Przejdź do okna Widok klasy, przechodząc do menu Widok i wybierając pozycję Widok klasy (lub wpisując Ctrl+Shift+C). W górnej połowie okna Widok klasy przejdź do przestrzeni nazw NorthwindTableAdapters i wybierz klasę ProductsTableAdapter. Wyświetli to elementy członkowskie ProductsTableAdapter w dolnej połowie widoku klasy, jak widać na rysunku 2. Kliknij dwukrotnie właściwość, Connection aby wyświetlić jej kod.

Double-Click właściwość Połączenia w Widoku Klasy, aby wyświetlić jego automatycznie wygenerowany kod

Rysunek 2. Double-Click Właściwość Połączenia w widoku klasy, aby wyświetlić jego automatycznie wygenerowany kod

Właściwość TableAdapter s Connection i inny kod związany z połączeniem są następujące:

private System.Data.SqlClient.SqlConnection _connection;
private void InitConnection() {
    this._connection = new System.Data.SqlClient.SqlConnection();
    this._connection.ConnectionString = 
        ConfigurationManager.ConnectionStrings["NORTHWNDConnectionString"].ConnectionString;
}
internal System.Data.SqlClient.SqlConnection Connection {
    get {
        if ((this._connection == null)) {
            this.InitConnection();
        }
        return this._connection;
    }
    set {
        this._connection = value;
        if ((this.Adapter.InsertCommand != null)) {
            this.Adapter.InsertCommand.Connection = value;
        }
        if ((this.Adapter.DeleteCommand != null)) {
            this.Adapter.DeleteCommand.Connection = value;
        }
        if ((this.Adapter.UpdateCommand != null)) {
            this.Adapter.UpdateCommand.Connection = value;
        }
        for (int i = 0; (i < this.CommandCollection.Length); i = (i + 1)) {
            if ((this.CommandCollection[i] != null)) {
                ((System.Data.SqlClient.SqlCommand)
                    (this.CommandCollection[i])).Connection = value;
            }
        }
    }
}

Po utworzeniu wystąpienia klasy TableAdapter, zmienna składowa _connection jest równa null. Podczas uzyskiwania dostępu do właściwości Connection, najpierw sprawdzane jest, czy zmienna składowa _connection została utworzona. Jeśli tak nie jest, metoda InitConnection jest wywoływana, która tworzy instancję _connection i ustawia jej właściwość ConnectionString na wartość parametrów połączenia określoną w pierwszym kroku kreatora konfiguracji TableAdapter.

Właściwość Connection można również przypisać do SqlConnection obiektu. Powoduje to skojarzenie nowego SqlConnection obiektu z każdym obiektem TableAdapter s SqlCommand .

Krok 2. Uwidacznianie ustawień Connection-Level

Informacje o połączeniu powinny pozostać hermetyzowane w tabeli TableAdapter i nie być dostępne dla innych warstw w architekturze aplikacji. Mogą jednak wystąpić sytuacje, w których informacje o poziomie połączenia usługi TableAdapter muszą być dostępne lub dostosowywalne dla strony zapytania, użytkownika lub ASP.NET.

Rozszerzmy ProductsTableAdapter w Northwind DataSet, aby uwzględnić właściwość ConnectionString, która może być używana przez warstwę logiki biznesowej do odczytywania lub zmieniania łańcucha połączenia używanego przez TableAdapter.

Uwaga / Notatka

Parametry połączenia to parametry, które określają informacje o połączeniu z bazą danych, takie jak dostawca do użycia, lokalizacja bazy danych, poświadczenia uwierzytelniania i inne ustawienia związane z bazą danych. Aby uzyskać listę wzorców parametrów połączenia używanych przez różne magazyny danych i dostawców, zobacz ConnectionStrings.com.

Zgodnie z opisem w samouczku Tworzenie warstwy dostępu do danych, automatycznie generowane klasy zbioru danych typu Typed DataSet można rozszerzyć za pomocą klas częściowych. Najpierw utwórz nowy podfolder w projekcie o nazwie ConnectionAndCommandSettings poniżej ~/App_Code/DAL folderu.

Dodawanie podfolderu o nazwie ConnectionAndCommandSettings

Rysunek 3. Dodawanie podfolderu o nazwie ConnectionAndCommandSettings

Dodaj nowy plik klasy o nazwie ProductsTableAdapter.ConnectionAndCommandSettings.cs i wprowadź następujący kod:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
namespace NorthwindTableAdapters
{
    public partial class ProductsTableAdapter
    {
        public string ConnectionString
        {
            get
            {
                return this.Connection.ConnectionString;
            }
            set
            {
                this.Connection.ConnectionString = value;
            }
        }
    }
}

Ta częściowa klasa public dodaje właściwość o nazwie ConnectionString do klasy ProductsTableAdapter, która umożliwia każdej warstwie odczytywanie lub aktualizowanie parametrów połączenia dla bazowego połączenia TableAdapter.

Po utworzeniu tej częściowej klasy (i zapisaniu) otwórz klasę ProductsBLL . Przejdź do jednej z istniejących metod, wpisz Adapter, a następnie naciśnij klawisz kropki, aby uruchomić IntelliSense. Powinna zostać wyświetlona nowa ConnectionString właściwość dostępna w funkcji IntelliSense, co oznacza, że można programowo odczytywać lub dostosowywać tę wartość z poziomu usługi BLL.

Uwidacznianie całego obiektu połączenia

Ta klasa częściowa uwidacznia tylko jedną właściwość bazowego obiektu połączenia: ConnectionString. Jeśli chcesz udostępnić cały obiekt połączenia poza zakresem TableAdaptera, możesz również zmienić poziom ochrony właściwości Connection. Wygenerowany automatycznie kod przedstawiony w kroku 1 wykazał, że właściwość Connection klasy TableAdapter jest oznaczona jako internal, co oznacza, że dostęp do niej można uzyskać tylko przez klasy w tej samej assemblacji. Można to jednak zmienić za pomocą właściwości TableAdaptera ConnectionModifier.

Otwórz zestaw Northwind danych, kliknij ProductsTableAdapter element w Projektancie i przejdź do okna Właściwości. Tam zobaczysz, jak ConnectionModifier jest ustawiany na jego wartość domyślną, Assembly. Aby udostępnić Connection właściwość poza zestawem Typed DataSet, zmień ConnectionModifier właściwość na Public.

Poziom dostępu właściwości połączenia można skonfigurować za pomocą właściwości ConnectionModifier

Rysunek 4. Connection Poziom ułatwień dostępu właściwości można skonfigurować za pomocą ConnectionModifier właściwości (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Zapisz zestaw danych, a następnie wróć do ProductsBLL klasy. Tak jak wcześniej, przejdź do jednej z istniejących metod i wpisz Adapter, a następnie naciśnij klawisz kropki, aby uruchomić funkcję IntelliSense. Lista powinna zawierać Connection właściwość, co oznacza, że można teraz programowo odczytywać lub przypisywać dowolne ustawienia na poziomie połączenia z poziomu BLL.

Element TableAdapter składa się z głównego zapytania, które domyślnie ma automatycznie generowane instrukcje INSERT, UPDATE i DELETE. To główne zapytanie INSERT, UPDATE, DELETE instrukcje są implementowane w kodzie TableAdapter jako obiekt ADO.NET adaptera danych poprzez właściwość Adapter. Podobnie jak w przypadku jej właściwości Connection, typ danych właściwości Adapter jest określany przez dostawcę danych, który jest używany. Ponieważ w tych samouczkach jest używany dostawca SqlClient, Adapter właściwość jest typu SqlDataAdapter.

Właściwość Adapter TableAdapter ma trzy właściwości typu SqlCommand, które używa do wystawiania instrukcji INSERT, UPDATE i DELETE.

  • InsertCommand
  • UpdateCommand
  • DeleteCommand

Obiekt SqlCommand jest odpowiedzialny za wysłanie określonego zapytania do bazy danych i ma właściwości takie jak: CommandText, która zawiera instrukcję AD hoc SQL lub procedurę składowaną do wykonania; i Parameters, która jest kolekcją SqlParameter obiektów. Jak widzieliśmy już w samouczku Tworzenie warstwy dostępu do danych , te obiekty poleceń można dostosować za pomocą okna Właściwości.

Oprócz głównego zapytania narzędzie TableAdapter może zawierać zmienną liczbę metod, które po wywołaniu wysyłają określone polecenie do bazy danych. Główny obiekt zapytania oraz obiekty poleceń dla wszystkich dodatkowych metod są przechowywane we właściwości CommandCollection TableAdaptera.

Przyjrzyjmy się kodowi wygenerowanemu przez ProductsTableAdapter element DataSet Northwind dla tych dwóch właściwości oraz ich pomocniczych zmiennych składowych i metod pomocniczych:

private System.Data.SqlClient.SqlDataAdapter _adapter;
private void InitAdapter() {
    this._adapter = new System.Data.SqlClient.SqlDataAdapter();
    
    ... Code that creates the InsertCommand, UpdateCommand, ...
    ... and DeleteCommand instances - omitted for brevity ...
}
private System.Data.SqlClient.SqlDataAdapter Adapter {
    get {
        if ((this._adapter == null)) {
            this.InitAdapter();
        }
        return this._adapter;
    }
}
private System.Data.SqlClient.SqlCommand[] _commandCollection;
private void InitCommandCollection() {
    this._commandCollection = new System.Data.SqlClient.SqlCommand[9];
    ... Code that creates the command objects for the main query and the ...
    ... ProductsTableAdapter�s other eight methods - omitted for brevity ...
}
protected System.Data.SqlClient.SqlCommand[] CommandCollection {
    get {
        if ((this._commandCollection == null)) {
            this.InitCommandCollection();
        }
        return this._commandCollection;
    }
}

Kod dla właściwości Adapter i CommandCollection ściśle naśladuje kod właściwości Connection. Istnieją zmienne składowe, które przechowują obiekty używane przez właściwości. Akcesory właściwości get zaczynają od sprawdzenia, czy odpowiadająca im zmienna składowa to null. Jeśli tak, wywoływana jest metoda inicjowania, która tworzy wystąpienie zmiennej składowej i przypisuje podstawowe właściwości związane z poleceniami.

Krok 4. Uwidacznianie ustawień Command-Level

W idealnym przypadku informacje na poziomie polecenia powinny pozostać hermetyzowane w warstwie dostępu do danych. Jeśli te informacje będą potrzebne w innych warstwach architektury, można je jednak uwidocznić za pośrednictwem klasy częściowej, podobnie jak w przypadku ustawień na poziomie połączenia.

Ponieważ obiekt TableAdapter ma tylko jedną Connection właściwość, kod do uwidaczniania ustawień na poziomie połączenia jest dość prosty. Modyfikacja ustawień na poziomie poleceń jest nieco bardziej skomplikowana, ponieważ TableAdapter może mieć wiele obiektów poleceń - InsertCommand, UpdateCommand i DeleteCommand, wraz ze zmienną liczbą obiektów poleceń w właściwości CommandCollection. Podczas aktualizowania ustawień na poziomie polecenia te ustawienia należy propagować do wszystkich obiektów poleceń.

Załóżmy na przykład, że w TableAdapterze istniały pewne zapytania, które wykonywały się niezwykle długo. Gdy używamy TableAdapter do wykonywania jednego z tych zapytań, możemy zwiększyć właściwość obiektu polecenia CommandTimeout. Ta właściwość określa liczbę sekund oczekiwania na wykonanie polecenia i domyślnie 30.

Aby umożliwić dostosowanie właściwości CommandTimeout przez BLL, dodaj następującą metodę public do ProductsDataTable, używając pliku klasy częściowej utworzonego w kroku 2 (ProductsTableAdapter.ConnectionAndCommandSettings.cs):

public void SetCommandTimeout(int timeout)
{
    if (this.Adapter.InsertCommand != null)
        this.Adapter.InsertCommand.CommandTimeout = timeout;
    if (this.Adapter.DeleteCommand != null)
        this.Adapter.DeleteCommand.CommandTimeout = timeout;
    if (this.Adapter.UpdateCommand != null)
        this.Adapter.UpdateCommand.CommandTimeout = timeout;
    for (int i = 0; i < this.CommandCollection.Length; i++)
        if (this.CommandCollection[i] != null)
            this.CommandCollection[i].CommandTimeout = timeout;
}

Tę metodę można wywołać z warstwy BLL lub warstwy prezentacji, aby ustawić limit czasu polecenia dla wszystkich poleceń wydawanych przez tę instancję TableAdapter.

Uwaga / Notatka

Właściwości Adapter i CommandCollection są oznaczone jako private, co oznacza, że można uzyskać do nich dostęp tylko z kodu w tabeli TableAdapter. Connection W przeciwieństwie do właściwości te modyfikatory dostępu nie są konfigurowalne. W związku z tym, jeśli musisz udostępnić właściwości na poziomie polecenia innym warstwom w architekturze, należy użyć podejścia z użyciem klasy częściowej omówionego powyżej, aby zapewnić metodę public lub właściwość, która odczytuje lub przypisuje wartości w obiektach poleceń private.

Podsumowanie

Klasy TableAdapters w typowanym zestawie danych służą do hermetyzacji szczegółów i złożoności dostępu do danych. Przy użyciu elementów TableAdapters nie musimy martwić się o pisanie kodu ADO.NET w celu nawiązania połączenia z bazą danych, wystawienia polecenia lub wypełnienia wyników w tabeli DataTable. To wszystko jest obsługiwane automatycznie dla nas.

Jednak mogą wystąpić sytuacje, w których musimy dostosować specyfiki ADO.NET na niskim poziomie, takie jak zmiana ciągu połączenia lub wartości domyślnego limitu czasu dla połączenia lub polecenia. Element TableAdapter ma automatycznie generowane właściwości Connection, Adapter i CommandCollection, ale te są domyślnie internal lub private. Te informacje wewnętrzne można uwidocznić przez rozszerzenie klasy TableAdapter przy użyciu klas częściowych w celu uwzględnienia public metod lub właściwości. Alternatywnie można skonfigurować modyfikator dostępu do właściwości TableAdapter's Connection za pomocą właściwości TableAdapter's ConnectionModifier.

Szczęśliwe programowanie!

Informacje o autorze

Scott Mitchell, autor siedmiu książek ASP/ASP.NET i założyciel 4GuysFromRolla.com, współpracuje z technologiami internetowymi firmy Microsoft od 1998 roku. Scott pracuje jako niezależny konsultant, trener i pisarz. Jego najnowsza książka to Sams Teach Yourself ASP.NET 2.0 w ciągu 24 godzin. Można go uzyskać pod adresem mitchell@4GuysFromRolla.com.

Specjalne podziękowania

Ta seria samouczków została omówiona przez wielu przydatnych recenzentów. Głównymi recenzentami tego samouczka byli Burnadette Leigh, Søren Jacob Lauritsen, Teresa Murphy i Hilton Geisenow. Chcesz przejrzeć nadchodzące artykuły MSDN? Jeśli tak, napisz do mnie na adres mitchell@4GuysFromRolla.com.