Udostępnij za pośrednictwem


Kontrolki źródła danych

autor: Microsoft

Kontrolka DataGrid w ASP.NET 1.x oznaczyła dużą poprawę dostępu do danych w aplikacjach internetowych. Nie było to jednak tak przyjazne dla użytkownika, jak mogło być. Nadal wymagana jest znaczna ilość kodu, aby uzyskać z niego wiele przydatnych funkcji. Jest to model we wszystkich przedsięwzięciach dotyczących dostępu do danych w wersji 1.x.

Kontrolka DataGrid w ASP.NET 1.x oznaczyła dużą poprawę dostępu do danych w aplikacjach internetowych. Nie było to jednak tak przyjazne dla użytkownika, jak mogło być. Nadal wymagana jest znaczna ilość kodu, aby uzyskać z niego wiele przydatnych funkcji. Jest to model we wszystkich przedsięwzięciach dotyczących dostępu do danych w wersji 1.x.

ASP.NET 2.0 częściowo rozwiązuje ten problem za pomocą kontrolek źródła danych. Kontrolki źródła danych w wersji ASP.NET 2.0 zapewniają deweloperom deklaratywny model pobierania danych, wyświetlania danych i edytowania danych. Celem kontrolek źródła danych jest zapewnienie spójnej reprezentacji danych do kontrolek powiązanych z danymi niezależnie od źródła tych danych. W centrum kontrolek źródła danych w ASP.NET 2.0 jest klasa abstrakcyjna DataSourceControl. Klasa DataSourceControl udostępnia podstawową implementację interfejsu IDataSource i interfejsu IListSource, z których druga umożliwia przypisanie kontrolki źródła danych jako źródła danych kontrolki powiązanej z danymi (za pośrednictwem nowej właściwości DataSourceId omówionej w dalszej części) i uwidocznienie tam danych jako listy. Każda lista danych z kontrolki źródła danych jest widoczna jako obiekt DataSourceView. Dostęp do wystąpień elementu DataSourceView jest udostępniany przez interfejs IDataSource. Na przykład metoda GetViewNames zwraca element ICollection, który umożliwia wyliczenie elementów DataSourceView skojarzonych z określoną kontrolą źródła danych, a metoda GetView umożliwia dostęp do określonego wystąpienia elementu DataSourceView według nazwy.

Kontrolki źródła danych nie mają interfejsu użytkownika. Są one implementowane jako kontrolki serwera, dzięki czemu mogą obsługiwać składnię deklaratywną i w razie potrzeby mieć dostęp do stanu strony. Kontrolki źródła danych nie renderują żadnych znaczników HTML do klienta.

Uwaga / Notatka

Jak zobaczymy później, istnieją również korzyści z buforowania uzyskane przy użyciu kontrolek źródła danych.

Przechowywanie parametrów połączenia

Zanim zaczniemy badać sposób konfigurowania kontrolek źródła danych, należy uwzględnić nową funkcję w ASP.NET 2.0 dotyczące parametrów połączenia. ASP.NET 2.0 wprowadza nową sekcję w pliku konfiguracji, która umożliwia łatwe przechowywanie parametrów połączenia, które mogą być odczytywane dynamicznie w czasie wykonywania. Sekcja <connectionStrings> ułatwia przechowywanie parametrów połączenia.

Poniższy fragment kodu dodaje nowe parametry połączenia.

<connectionStrings> <add name="Northwind" connectionString="Data Source=localhost; Integrated Security=SSPI;Initial Catalog=Northwind;" providerName="System.Data.SqlClient" /> </connectionStrings>

Uwaga / Notatka

Podobnie jak w <sekcji >appSettings< sekcja connectionStrings> pojawia się poza <sekcją system.web> w pliku konfiguracji.

Aby użyć tych parametrów połączenia, można użyć następującej składni podczas ustawiania atrybutu ConnectionString kontrolki serwera.

ConnectionString="<%$ ConnectionStrings:Northwind%>"

<Sekcja connectionStrings> może być również zaszyfrowana, aby poufne informacje nie są ujawniane. Ta możliwość zostanie omówiona w późniejszym module.

Buforowanie źródeł danych

Każda funkcja DataSourceControl udostępnia cztery właściwości do konfigurowania buforowania; EnableCaching, CacheDuration, CacheExpirationPolicy i CacheKeyDependency.

EnableCaching

EnableCaching to właściwość logiczna określająca, czy buforowanie jest włączone dla kontrolki źródła danych.

Właściwość CacheDuration

Właściwość CacheDuration ustawia liczbę sekund, przez które pamięć podręczna pozostaje prawidłowa. Ustawienie tej właściwości na 0 powoduje, że pamięć podręczna pozostanie prawidłowa do momentu jawnego unieważnienia.

Właściwość CacheExpirationPolicy

Właściwość CacheExpirationPolicy można ustawić na bezwzględna lub przesuwana. Ustawienie wartości Bezwzględne oznacza, że maksymalny czas buforowania danych to liczba sekund określona przez właściwość CacheDuration. Ustawiając go na Przesuwanie, czas wygaśnięcia jest resetowany po wykonaniu każdej operacji.

Właściwość CacheKeyDependency

Jeśli dla właściwości CacheKeyDependency określono wartość ciągu, ASP.NET skonfiguruje nową zależność pamięci podręcznej na podstawie tego ciągu. Dzięki temu można jawnie unieważnić pamięć podręczną, zmieniając lub usuwając element CacheKeyDependency.

Ważne: jeśli jest włączone podszywanie się, a dostęp do źródła danych i/lub zawartości danych jest oparty na tożsamości klienta, zaleca się wyłączenie buforowania przez ustawienie EnableCaching na False. Jeśli buforowanie jest włączone w tym scenariuszu, a użytkownik inny niż użytkownik, który pierwotnie zażądał danych, wysyła żądanie, autoryzacja do źródła danych nie jest wymuszana. Dane będą po prostu serwowane z pamięci podręcznej.

Kontrolka SqlDataSource

Kontrolka SqlDataSource umożliwia deweloperowi dostęp do danych przechowywanych w dowolnej relacyjnej bazie danych, która obsługuje ADO.NET. Za pomocą dostawcy System.Data.SqlClient można uzyskać dostęp do bazy danych programu SQL Server, dostawcy System.Data.OleDb, dostawcy System.Data.Odbc lub dostawcy System.Data.OracleClient w celu uzyskania dostępu do bazy danych Oracle. W związku z tym źródło SqlDataSource z pewnością nie jest używane tylko do uzyskiwania dostępu do danych w bazie danych programu SQL Server.

Aby użyć elementu SqlDataSource, wystarczy podać wartość właściwości ConnectionString i określić polecenie SQL lub procedurę składowaną. Kontrolka SqlDataSource zajmuje się pracą z podstawową architekturą ADO.NET. Otwiera połączenie, wysyła zapytanie do źródła danych lub wykonuje procedurę składowaną, zwraca dane, a następnie zamyka połączenie za Ciebie.

Uwaga / Notatka

Ponieważ klasa DataSourceControl automatycznie zamyka połączenie, powinna zmniejszyć liczbę zgłoszeń klientów generowanych przez wyciek połączeń z bazą danych.

Poniższy fragment kodu wiąże kontrolkę DropDownList z kontrolką SqlDataSource przy użyciu parametrów połączenia przechowywanych w pliku konfiguracji, jak pokazano powyżej.

<asp:SqlDataSource id="SqlDataSource1" runat="server" DataSourceMode="DataReader" ConnectionString="<%$ ConnectionStrings:Northwind%>" SelectCommand="SELECT EmployeeID, LastName FROM Employees"> </asp:SqlDataSource><asp:DropDownList id="ListBox1" runat="server" DataTextField="LastName" DataValueField="EmployeeID" DataSourceID="SqlDataSource1"> </asp:DropDownList>

Jak pokazano powyżej, właściwość DataSourceMode źródła danych SqlDataSource określa tryb źródła danych. W powyższym przykładzie DataSourceMode jest ustawione na DataReader. W takim przypadku źródło SqlDataSource zwróci obiekt IDataReader przy użyciu kursora, który jest skierowany tylko do przodu i służy wyłącznie do odczytu. Określony typ zwracanego obiektu jest kontrolowany przez dostawcę, który jest używany. W tym przypadku używam dostawcy System.Data.SqlClient, jak określono w <sekcji connectionStrings> pliku web.config. W związku z tym zwracany obiekt będzie typu SqlDataReader. Określając wartość DataSourceMode elementu DataSet, dane mogą być przechowywane w zestawie danych na serwerze. Ten tryb umożliwia dodawanie funkcji, takich jak sortowanie, stronicowanie itp. Gdybym wiązał dane sqlDataSource z kontrolką GridView, wybrałbym tryb Zestawu danych. Jednak w przypadku listy rozwijanej tryb DataReader jest prawidłowym wyborem.

Uwaga / Notatka

Podczas buforowania elementu SqlDataSource lub AccessDataSource właściwość DataSourceMode musi być ustawiona na DataSet. Jeśli włączysz buforowanie w trybie DataSourceMode w DataReader, wystąpi wyjątek.

Właściwości sqlDataSource

Poniżej przedstawiono niektóre właściwości kontrolki SqlDataSource.

AnulujWybórPrzyBrakuParametru

Wartość logiczna określająca, czy polecenie select jest anulowane, jeśli jeden z parametrów ma wartość null. Domyślnie true.

WykrywanieKonfliktów

W sytuacji, gdy wielu użytkowników może jednocześnie aktualizować źródło danych, właściwość ConflictDetection określa zachowanie kontrolki SqlDataSource. Ta właściwość przyjmuje jedną z wartości wyliczenia ConflictOptions. Te wartości to CompareAllValues i OverwriteChanges. Jeśli ustawiono wartość OverwriteChanges, ostatnia osoba, która zapisuje dane w źródle danych, zastępuje wszelkie poprzednie zmiany. Jeśli jednak właściwość ConflictDetection jest ustawiona na CompareAllValues, parametry są tworzone dla kolumn zwracanych przez polecenie SelectCommand i parametry są również tworzone w celu przechowywania oryginalnych wartości w każdej z tych kolumn, co pozwala usłudze SqlDataSource określić, czy wartości zostały zmienione od czasu wykonania polecenia SelectCommand.

DeleteCommand

Ustawia lub pobiera ciąg SQL używany podczas usuwania wierszy z bazy danych. Może to być zapytanie SQL lub nazwa procedury składowanej.

DeleteCommandType

Ustawia lub pobiera typ polecenia usuwania — zapytanie SQL (tekst) lub procedurę składowaną (StoredProcedure).

Usuń parametry

Zwraca parametry używane przez polecenie DeleteCommand obiektu SqlDataSourceView skojarzonego z kontrolką SqlDataSourceSource.

OldValuesParameterFormatString

Ta właściwość służy do określania formatu oryginalnych parametrów wartości w przypadkach, gdy właściwość ConflictDetection jest ustawiona na CompareAllValues. Wartość domyślna oznacza {0} , że oryginalne parametry wartości będą przyjmować taką samą nazwę jak oryginalny parametr. Innymi słowy, jeśli nazwa pola to EmployeeID, oryginalny parametr wartości to @EmployeeID.

SelectCommand

Ustawia lub pobiera ciąg SQL używany do pobierania danych z bazy danych. Może to być zapytanie SQL lub nazwa procedury składowanej.

Wybierz typ polecenia

Ustawia lub pobiera typ polecenia select, zapytanie SQL (Text) lub procedurę składowaną.

WybierzParametry

Zwraca parametry używane przez polecenie SelectCommand obiektu SqlDataSourceView skojarzonego z kontrolką SqlDataSourceSource.

NazwaParametruSortowania

Pobiera lub ustawia nazwę parametru procedury składowanej używanego podczas sortowania danych pobranych przez kontrolę źródła danych. Prawidłowy tylko wtedy, gdy właściwość SelectCommandType jest ustawiona na StoredProcedure.

Sqlcachedependency

Rozdzielany średnikami ciąg określający bazy danych i tabele używane w zależności pamięci podręcznej programu SQL Server. (Zależności pamięci podręcznej SQL zostaną omówione w późniejszym module).

UpdateCommand

Ustawia lub pobiera ciąg SQL używany podczas aktualizowania danych w bazie danych. Może to być zapytanie SQL lub nazwa procedury składowanej.

UpdateCommandType

Ustawia lub pobiera typ polecenia aktualizacji — zapytanie SQL (tekst) lub procedurę składowaną (StoredProcedure).

UpdateParameters

Zwraca parametry używane przez polecenie UpdateCommand obiektu SqlDataSourceView skojarzonego z kontrolką SqlDataSourceSource.

Kontrolka AccessDataSource

Kontrolka AccessDataSource pochodzi z klasy SqlDataSource i służy do powiązania danych z bazą danych programu Microsoft Access. Właściwość ConnectionString kontrolki AccessDataSource jest właściwością tylko do odczytu. Zamiast używać właściwości ConnectionString, właściwość DataFile jest używana do wskazywania bazy danych programu Access, jak pokazano poniżej.

<asp:AccessDataSource id="AccessDataSource1" runat="server" DataFile="~/App_Data/Northwind.mdb"> </asp:AccessDataSource>

Źródło AccessDataSource zawsze ustawia nazwę ProviderName podstawowego elementu SqlDataSource na System.Data.OleDb i nawiązuje połączenie z bazą danych przy użyciu dostawcy Microsoft.Jet.OLEDB.4.0 OLE DB. Nie można użyć kontrolki AccessDataSource, aby nawiązać połączenie z bazą danych programu Access chronioną hasłem. Jeśli musisz nawiązać połączenie z bazą danych chronioną hasłem, użyj kontrolki SqlDataSource.

Uwaga / Notatka

Bazy danych programu Access przechowywane w witrynie sieci Web należy umieścić w katalogu App_Data. ASP.NET nie zezwala na przeglądanie plików w tym katalogu. Korzystając z baz danych Access, musisz przyznać kontu procesu uprawnienia do odczytu i zapisu w katalogu App_Data.

Kontrolka XmlDataSource

XmlDataSource służy do powiązania danych XML z kontrolkami obiektów danych. Plik XML można powiązać przy użyciu właściwości DataFile lub powiązać z ciągiem XML przy użyciu właściwości Data. Źródło XmlDataSource uwidacznia atrybuty XML jako pola możliwe do powiązania. W przypadkach, gdy konieczne jest powiązanie z wartościami, które nie są reprezentowane jako atrybuty, należy użyć przekształcenia XSL. Możesz również użyć wyrażeń XPath do filtrowania danych XML.

Rozważ następujący plik XML:

<?xml version="1.0" encoding="utf-8" ?> <People> <Person FirstName="Jake" LastName="Stone"> <Address> <Street>345 Maple St.</Street> <City>Redmond</City> <Region>WA</Region> <ZipCode>01434</ZipCode> </Address> <Job> <Title>CEO</Title> <Description>Develops company strategies.</Description> </Job> </Person> <Person FirstName="Jacob" LastName="Ladder"> <Address> <Street>123 Elm St.</Street> <City>Seattle</City> <Region>WA</Region> <ZipCode>11223</ZipCode> </Address> <Job> <Title>Attorney</Title> <Description>Reviews legal issues.</Description> </Job> </Person> <Person FirstName="Angela" LastName="Hound"> <Address> <Street>34 Palm Avenue</Street> <City>Renton</City> <Region>WA</Region> <ZipCode>63910</ZipCode> </Address> <Job> <Title>IT Director</Title> <Description>In charge of corporate network.</Description> </Job> </Person> </People>

Zwróć uwagę, że źródło XmlDataSource używa właściwości XPath People/Person w celu filtrowania na węzły <Person>. DropDownList następnie wiąże dane do atrybutu LastName za pomocą właściwości DataTextField.

Chociaż kontrolka XmlDataSource jest używana głównie do wiązania z danymi XML tylko do odczytu, można także edytować plik XML. Należy pamiętać, że w takich przypadkach automatyczne wstawianie, aktualizowanie i usuwanie informacji w pliku XML nie jest wykonywane automatycznie, podobnie jak w przypadku innych kontrolek źródła danych. Zamiast tego należy napisać kod, aby ręcznie edytować dane przy użyciu następujących metod kontrolki XmlDataSource.

GetXmlDocument

Pobiera obiekt XmlDocument zawierający kod XML pobrany przez źródło XmlDataSource.

Zapisz

Zapisuje plik XmlDocument w pamięci z powrotem do źródła danych.

Należy pamiętać, że metoda Save będzie działać tylko wtedy, gdy zostaną spełnione następujące dwa warunki:

  1. Źródło XmlDataSource używa właściwości DataFile do powiązania z plikiem XML zamiast właściwości Data w celu powiązania z danymi XML w pamięci.
  2. Nie określono przekształcenia za pomocą właściwości Transform lub TransformFile.

Należy również pamiętać, że metoda Save może zwracać nieoczekiwane wyniki w przypadku wywołania przez wielu użytkowników jednocześnie.

Kontrolka ObjectDataSource

Kontrolki źródła danych, które omówiliśmy do tego momentu, są doskonałymi wyborami dla aplikacji dwuwarstwowych, w których kontrola źródła danych komunikuje się bezpośrednio z magazynem danych. Jednak wiele rzeczywistych aplikacji to wielowarstwowe aplikacje, w których kontrola źródła danych może wymagać komunikacji z obiektem biznesowym, który z kolei komunikuje się z warstwą danych. W takich sytuacjach obiekt ObjectDataSource doskonale spełnia swoje zadanie. Obiekt ObjectDataSource działa w połączeniu z obiektem źródłowym. Kontrolka ObjectDataSource utworzy wystąpienie obiektu źródłowego, wywoła określoną metodę i usunie wystąpienie obiektu w zakresie pojedynczego żądania, jeśli obiekt ma metody wystąpienia zamiast metod statycznych (udostępnione w Visual Basic). W związku z tym obiekt musi być bezstanowy. Oznacza to, że obiekt powinien pozyskać i zwolnić wszystkie wymagane zasoby w ciągu jednego żądania. Możesz kontrolować sposób tworzenia obiektu źródłowego, obsługując zdarzenie ObjectCreating kontrolki ObjectDataSource. Możesz utworzyć wystąpienie obiektu źródłowego, a następnie ustawić właściwość ObjectInstance klasy ObjectDataSourceEventArgs na to wystąpienie. Kontrolka ObjectDataSource będzie używać wystąpienia utworzonego w zdarzeniu ObjectCreating zamiast tworzenia wystąpienia samodzielnie.

Jeśli obiekt źródłowy kontrolki ObjectDataSource uwidacznia publiczne metody statyczne (udostępnione w Visual Basic), które można wywołać w celu pobierania i modyfikowania danych, kontrolka ObjectDataSource wywoła te metody bezpośrednio. Jeśli kontrolka ObjectDataSource musi utworzyć wystąpienie obiektu źródłowego w celu wywołania metody, obiekt musi zawierać publiczny konstruktor, który nie przyjmuje parametrów. Kontrolka ObjectDataSource wywoła ten konstruktor podczas tworzenia nowego wystąpienia obiektu źródłowego.

Jeśli obiekt źródłowy nie zawiera publicznego konstruktora bez parametrów, możesz utworzyć wystąpienie obiektu źródłowego, które będzie używane przez kontrolkę ObjectDataSource w zdarzeniu ObjectCreating.

Określanie metod obiektów

Obiekt źródłowy kontrolki ObjectDataSource może zawierać dowolną liczbę metod używanych do wybierania, wstawiania, aktualizowania lub usuwania danych. Metody te są wywoływane przez kontrolkę ObjectDataSource na podstawie nazwy metody zidentyfikowanej przy użyciu kontrolki SelectMethod, InsertMethod, UpdateMethod lub DeleteMethod kontrolki ObjectDataSource. Obiekt źródłowy może również zawierać opcjonalną metodę SelectCount, która jest identyfikowana przez kontrolkę ObjectDataSource przy użyciu właściwości SelectCountMethod, która zwraca całkowitą liczbę obiektów w źródle danych. Kontrolka ObjectDataSource wywoła metodę SelectCount po wywołaniu metody Select w celu pobrania całkowitej liczby rekordów w źródle danych do użycia podczas stronicowania.

Laboratorium korzystające z kontrolek źródła danych

Ćwiczenie 1 — wyświetlanie danych za pomocą kontrolki SqlDataSource

W poniższym ćwiczeniu użyto kontrolki SqlDataSource do nawiązania połączenia z bazą danych Northwind. Zakłada się, że masz dostęp do bazy danych Northwind na serwerze SQL Server 2000.

  1. Utwórz nową witrynę ASP.NET sieci Web.

  2. Dodaj nowy plik web.config.

    1. Kliknij prawym przyciskiem myszy projekt w Eksploratorze rozwiązań i kliknij polecenie Dodaj nowy element.
    2. Wybierz pozycję Plik konfiguracji sieci Web z listy szablonów i kliknij przycisk Dodaj.
  3. Edytuj sekcję connectionStrings< w >następujący sposób:

    <asp:SqlDataSource ID="SqlDataSource1" runat="server"
        ConnectionString="<%$ConnectionStrings:Northwind%>"
        SelectCommand="SELECT * FROM Products">
    </asp:SqlDataSource>
    
  4. Przejdź do widoku Kod i dodaj atrybut ConnectionString i atrybut SelectCommand do <kontrolki asp:SqlDataSource> w następujący sposób:

    <asp:SqlDataSource ID="SqlDataSource1" runat="server"
        ConnectionString="<%$ConnectionStrings:Northwind%>"
        SelectCommand="SELECT * FROM Products">
    </asp:SqlDataSource>
    
  5. W widoku Projektu dodaj nową kontrolkę GridView.

  6. Z listy rozwijanej Wybierz źródło danych w menu Zadania obiektu GridView wybierz pozycję SqlDataSource1.

  7. Kliknij prawym przyciskiem myszy Default.aspx i wybierz pozycję Widok w przeglądarce z menu. Po wyświetleniu monitu o zapisanie kliknij przycisk Tak.

  8. Kontrolka GridView wyświetla dane z tabeli Products.

Ćwiczenie 2 . Edytowanie danych za pomocą kontrolki SqlDataSource

W poniższym ćwiczeniu pokazano, jak powiązać dane z kontrolką DropDownList przy użyciu składni deklaratywnej i umożliwia edytowanie danych przedstawionych w kontrolce DropDownList.

  1. W widoku Projekt usuń kontrolkę GridView z Default.aspx.

    Ważne: pozostaw kontrolkę SqlDataSource na stronie.

  2. Dodaj kontrolkę DropDownList do Default.aspx.

  3. Przełącz się do widoku źródła.

  4. Dodaj atrybut DataSourceId, DataTextField i DataValueField do kontrolki <asp:DropDownList> w następujący sposób:

    <asp:DropDownList ID="ddlProducts" runat="server"
         DataSourceId="SqlDataSource1" DataTextField="ProductName"
         DataValueField="ProductID">
    </asp:DropDownList>
    
  5. Zapisz Default.aspx i wyświetl go w przeglądarce. Zwróć uwagę, że lista DropDownList zawiera wszystkie produkty z bazy danych Northwind.

  6. Zamknij okno przeglądarki.

  7. W Widoku Źródła Default.aspx dodaj nową kontrolkę TextBox poniżej kontrolki DropDownList. Zmień właściwość ID pola TextBox na txtProductName.

  8. Pod kontrolką TextBox dodaj nową kontrolkę Przycisk. Zmień właściwość ID przycisku na btnUpdate i właściwość Text na Aktualizuj nazwę produktu.

  9. W widoku Źródło Default.aspx dodaj właściwość UpdateCommand i dwa nowe parametry UpdateParameters do tagu SqlDataSource w następujący sposób:

    <asp:SqlDataSource ID="SqlDataSource1" runat="server"
        ConnectionString="<%$ConnectionStrings:Northwind%>"
        SelectCommand="SELECT * FROM Products"
        UpdateCommand="UPDATE Products SET ProductName=@ProductName WHERE ProductID=@ProductID">
          <UpdateParameters>
          <asp:ControlParameter Name="ProductName" 
            ControlID="txtProductName" PropertyName="Text" />
          <asp:ControlParameter Name="ProductID" 
            ControlID="ddlProducts" PropertyName="SelectedValue" />
    </asp:SqlDataSource>
    

    Uwaga / Notatka

    Należy pamiętać, że w tym kodzie dodano dwa parametry aktualizacji (ProductName i ProductID). Te parametry są mapowane na właściwość Tekst pola tekstowego txtProductName oraz na właściwość WybranaWartość listy rozwijanej ddlProducts.

  10. Przejdź do widoku projektu i kliknij dwukrotnie kontrolkę Przycisk, aby dodać procedurę obsługi zdarzeń.

  11. Dodaj następujący kod do kodu btnUpdate_Click:

    SqlDataSource1.Update();
    
  12. Kliknij prawym przyciskiem myszy na Default.aspx i wybierz opcję wyświetlenia w przeglądarce. Po wyświetleniu monitu o zapisanie wszystkich zmian kliknij przycisk Tak.

  13. W ASP.NET 2.0 klasy częściowe pozwalają na kompilację w czasie wykonywania. Nie trzeba kompilować aplikacji, aby zobaczyć, że zmiany kodu zaczną obowiązywać.

  14. Wybierz produkt z listy rozwijanej.

  15. Wprowadź nową nazwę wybranego produktu w polu tekstowym, a następnie kliknij przycisk Aktualizuj.

  16. Nazwa produktu jest aktualizowana w bazie danych.

Ćwiczenie 3 przy użyciu kontrolki ObjectDataSource

W tym ćwiczeniu pokazano, jak używać kontrolki ObjectDataSource i obiektu źródłowego do interakcji z bazą danych Northwind.

  1. Kliknij prawym przyciskiem myszy projekt w Eksploratorze rozwiązań i kliknij polecenie Dodaj nowy element.

  2. Wybierz pozycję Formularz internetowy na liście szablonów. Zmień nazwę na object.aspx i kliknij przycisk Dodaj.

  3. Kliknij prawym przyciskiem myszy projekt w Eksploratorze rozwiązań i kliknij polecenie Dodaj nowy element.

  4. Wybierz pozycję Klasa na liście szablonów. Zmień nazwę klasy na NorthwindData.cs i kliknij przycisk Dodaj.

  5. Po wyświetleniu monitu o dodanie klasy do folderu App_Code kliknij przycisk Tak.

  6. Dodaj następujący kod do pliku NorthwindData.cs:

    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;
    using System.Data.SqlClient;
    public class NorthwindData {
        private string _connectionString;
        public NorthwindData() {
            Initialize();
        }
    
        private void Initialize() {
            if (ConfigurationManager.ConnectionStrings["Northwind"] == null ||
                ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString.Trim() == "") {
                    throw new Exception("A connection string named 'Northwind' with " +
                    "a valid connection string must exist in the <connectionStrings> " +
                    "configuration section for the application.");
            }
            _connectionString = ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;
        }
    
        public DataTable GetAllEmployees(string sortColumns, int startRecord, int maxRecords) {
            VerifySortColumns(sortColumns);
            string sqlCmd = "SELECT EmployeeID, LastName, FirstName, Address, " +
                "City, Region, PostalCode FROM Employees ";
            if (sortColumns.Trim() == "")
                sqlCmd += "ORDER BY EmployeeID";
            else
                sqlCmd += "ORDER BY " + sortColumns;
    
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlDataAdapter da = new SqlDataAdapter(sqlCmd, conn);
            DataSet ds = new DataSet();
            try {
                conn.Open();
                da.Fill(ds, startRecord, maxRecords, "Employees");
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
            return ds.Tables["Employees"];
        }
    
        public int SelectCount() {
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlCommand cmd = new SqlCommand("SELECT COUNT(*) FROM Employees", conn);
            int result = 0;
    
            try {
                conn.Open();
                result = (int)cmd.ExecuteScalar();
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
            return result;
        }
    
        //////////
        // Verify that only valid columns are specified in the sort expression to
        // avoid a SQL Injection attack.
        private void VerifySortColumns(string sortColumns) {
            if (sortColumns.ToLowerInvariant().EndsWith(" desc"))
                sortColumns = sortColumns.Substring(0, sortColumns.Length - 5);
            string[] columnNames = sortColumns.Split(',');
            foreach (string columnName in columnNames) {
                switch (columnName.Trim().ToLowerInvariant()) {
                    case "employeeid":
                        break;
                    case "lastname":
                        break;
                    case "firstname":
                        break;
                    case "":
                        break;
                    default:
                        throw new ArgumentException("SortColumns contains an " +
                            "invalid column name.");
                        break;
                }
            }
        }
    
        // Select an employee.
        public DataTable GetEmployee(int EmployeeID) {
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlDataAdapter da =
                new SqlDataAdapter("SELECT EmployeeID, LastName, FirstName, " +
                "Address, City, Region, PostalCode " +
                " FROM Employees WHERE EmployeeID = @EmployeeID", conn);
            da.SelectCommand.Parameters.Add("@EmployeeID", SqlDbType.Int).Value = EmployeeID;
            DataSet ds = new DataSet();
            try {
                conn.Open();
                da.Fill(ds, "Employees");
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
    
            return ds.Tables["Employees"];
        }
    
        // Delete the Employee by ID.
        public int DeleteEmployee(int EmployeeID) {
             SqlConnection conn = new SqlConnection(_connectionString);
             SqlCommand cmd = new SqlCommand("DELETE FROM Employees WHERE " +
                 "EmployeeID = @EmployeeID", conn);
             cmd.Parameters.Add("@EmployeeID", SqlDbType.Int).Value = EmployeeID;
             int result = 0;
             try {
                 conn.Open();
                 result = cmd.ExecuteNonQuery();
             } catch (SqlException e) {
                 // Handle exception.
             } finally {
                 conn.Close();
             }
    
             return result;
         }
    
         // Update the Employee by original ID.
         public int UpdateEmployee(int EmployeeID, string LastName, string FirstName,
             string Address, string City, string Region,
             string PostalCode) {
             if (String.IsNullOrEmpty(FirstName))
                 throw new ArgumentException("FirstName cannot be null or an empty string.");
             if (String.IsNullOrEmpty(LastName))
                 throw new ArgumentException("LastName cannot be null or an empty string.");
             if (Address == null) { Address = String.Empty; }
             if (City == null) { City = String.Empty; }
             if (Region == null) { Region = String.Empty; }
             if (PostalCode == null) { PostalCode = String.Empty; }
    
             SqlConnection conn = new SqlConnection(_connectionString);
             SqlCommand cmd = new SqlCommand("UPDATE Employees " +
                 " SET FirstName=@FirstName, " +
                 "LastName=@LastName, " +
                 "Address=@Address, City=@City, " +
                 "Region=@Region, " +
                 "PostalCode=@PostalCode " +
                 "WHERE EmployeeID=@EmployeeID", conn);
             cmd.Parameters.Add("@FirstName", SqlDbType.VarChar, 10).Value = FirstName;
             cmd.Parameters.Add("@LastName", SqlDbType.VarChar, 20).Value = LastName;
             cmd.Parameters.Add("@Address", SqlDbType.VarChar, 60).Value = Address;
             cmd.Parameters.Add("@City", SqlDbType.VarChar, 15).Value = City;
             cmd.Parameters.Add("@Region", SqlDbType.VarChar, 15).Value = Region;
             cmd.Parameters.Add("@PostalCode", SqlDbType.VarChar, 10).Value = PostalCode;
             cmd.Parameters.Add("@EmployeeID", SqlDbType.Int).Value = EmployeeID;
    
             int result = 0;
             try {
                 conn.Open();
                 result = cmd.ExecuteNonQuery();
             } catch (SqlException e) {
                 // Handle exception.
             } finally {
                 conn.Close();
             }
    
             return result;
        }
    
        // Insert an Employee.
        public int InsertEmployee(string LastName, string FirstName,
            string Address, string City, string Region,
            string PostalCode) {
            if (String.IsNullOrEmpty(FirstName))
                throw new ArgumentException("FirstName cannot be null or an empty string.");
            if (String.IsNullOrEmpty(LastName))
                throw new ArgumentException("LastName cannot be null or an empty string.");
            if (Address == null) { Address = String.Empty; }
            if (City == null) { City = String.Empty; }
            if (Region == null) { Region = String.Empty; }
            if (PostalCode == null) { PostalCode = String.Empty; }
    
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlCommand cmd = new SqlCommand("INSERT INTO Employees " +
                " (FirstName, LastName, Address, " +
                " City, Region, PostalCode) " +
                " Values(@FirstName, @LastName, " +
                "@Address, @City, @Region, @PostalCode); " +
                "SELECT @EmployeeID = SCOPE_IDENTITY()", conn);
    
            cmd.Parameters.Add("@FirstName", SqlDbType.VarChar, 10).Value = FirstName;
            cmd.Parameters.Add("@LastName", SqlDbType.VarChar, 20).Value = LastName;
            cmd.Parameters.Add("@Address", SqlDbType.VarChar, 60).Value = Address;
            cmd.Parameters.Add("@City", SqlDbType.VarChar, 15).Value = City;
            cmd.Parameters.Add("@Region", SqlDbType.VarChar, 15).Value = Region;
            cmd.Parameters.Add("@PostalCode", SqlDbType.VarChar, 10).Value = PostalCode;
            SqlParameter p = cmd.Parameters.Add("@EmployeeID", SqlDbType.Int);
                p.Direction = ParameterDirection.Output;
            int newEmployeeID = 0;
            try {
                conn.Open();
                cmd.ExecuteNonQuery();
                newEmployeeID = (int)p.Value;
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
    
            return newEmployeeID;
        }
    
        //
        // Methods that support Optimistic Concurrency checks.
        //
        // Delete the Employee by ID.
        public int DeleteEmployee(int original_EmployeeID, string original_LastName,
            string original_FirstName, string original_Address,
            string original_City, string original_Region,
            string original_PostalCode) {
    
            if (String.IsNullOrEmpty(original_FirstName))
                throw new ArgumentException("FirstName cannot be null or an empty string.");
            if (String.IsNullOrEmpty(original_LastName))
                throw new ArgumentException("LastName cannot be null or an empty string.");
            if (original_Address == null) { original_Address = String.Empty; }
            if (original_City == null) { original_City = String.Empty; }
            if (original_Region == null) { original_Region = String.Empty; }
            if (original_PostalCode == null) { original_PostalCode = String.Empty; }
            string sqlCmd = "DELETE FROM Employees WHERE EmployeeID = " + @original_EmployeeID
    
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlCommand cmd = new SqlCommand(sqlCmd, conn);
            cmd.Parameters.Add("@original_EmployeeID",
                SqlDbType.Int).Value = original_EmployeeID;
            cmd.Parameters.Add("@original_FirstName",
                SqlDbType.VarChar, 10).Value = original_FirstName;
            cmd.Parameters.Add("@original_LastName",
                SqlDbType.VarChar, 20).Value = original_LastName;
            cmd.Parameters.Add("@original_Address",
                SqlDbType.VarChar, 60).Value = original_Address;
            cmd.Parameters.Add("@original_City",
                SqlDbType.VarChar, 15).Value = original_City;
            cmd.Parameters.Add("@original_Region",
                SqlDbType.VarChar, 15).Value = original_Region;
            cmd.Parameters.Add("@original_PostalCode",
                SqlDbType.VarChar, 10).Value = original_PostalCode;
    
            int result = 0;
            try {
                conn.Open();
                result = cmd.ExecuteNonQuery();
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
    
            return result;
        }
    
        // Update the Employee by original ID.
        public int UpdateEmployee(string LastName, string FirstName,
            string Address, string City, string Region,
            string PostalCode, int original_EmployeeID,
            string original_LastName, string original_FirstName,
            string original_Address, string original_City,
            string original_Region, string original_PostalCode) {
    
            if (String.IsNullOrEmpty(FirstName))
                throw new ArgumentException("FirstName cannot be null or an empty string.");
            if (String.IsNullOrEmpty(LastName))
                throw new ArgumentException("LastName cannot be null or an empty string.");
            if (Address == null) { Address = String.Empty; }
            if (City == null) { City = String.Empty; }
            if (Region == null) { Region = String.Empty; }
            if (PostalCode == null) { PostalCode = String.Empty; }
            if (original_Address == null) { original_Address = String.Empty; }
            if (original_City == null) { original_City = String.Empty; }
            if (original_Region == null) { original_Region = String.Empty; }
            if (original_PostalCode == null) { original_PostalCode = String.Empty; }
    
            string sqlCmd = "UPDATE Employees " +
                " SET FirstName = @FirstName, LastName = @LastName, " +
                " Address = @Address, City = @City, Region = @Region, " +
                " PostalCode = @PostalCode " +
                " WHERE EmployeeID = @original_EmployeeID";
    
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlCommand cmd = new SqlCommand(sqlCmd, conn);
            cmd.Parameters.Add("@FirstName", SqlDbType.VarChar, 10).Value = FirstName;
            cmd.Parameters.Add("@LastName", SqlDbType.VarChar, 20).Value = LastName;
            cmd.Parameters.Add("@Address", SqlDbType.VarChar, 60).Value = Address;
            cmd.Parameters.Add("@City", SqlDbType.VarChar, 15).Value = City;
            cmd.Parameters.Add("@Region", SqlDbType.VarChar, 15).Value = Region;
            cmd.Parameters.Add("@PostalCode", SqlDbType.VarChar, 10).Value = PostalCode;
            cmd.Parameters.Add("@original_EmployeeID",
                SqlDbType.Int).Value = original_EmployeeID;
            cmd.Parameters.Add("@original_FirstName",
                SqlDbType.VarChar, 10).Value = original_FirstName;
            cmd.Parameters.Add("@original_LastName",
                SqlDbType.VarChar, 20).Value = original_LastName;
            cmd.Parameters.Add("@original_Address",
                SqlDbType.VarChar, 60).Value = original_Address;
            cmd.Parameters.Add("@original_City",
                SqlDbType.VarChar, 15).Value = original_City;
            cmd.Parameters.Add("@original_Region",
                SqlDbType.VarChar, 15).Value = original_Region;
            cmd.Parameters.Add("@original_PostalCode",
                SqlDbType.VarChar, 10).Value = original_PostalCode;
    
            int result = 0;
    
            try {
                conn.Open();
                result = cmd.ExecuteNonQuery();
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
            return result;
        }
    }
    
  7. Dodaj następujący kod do widoku źródłowego object.aspx:

    <%@ Page language="C#" %>
    <script RunAt="server">
    void EmployeesDetailsView_ItemInserted(Object sender, DetailsViewInsertedEventArgs e) {
        EmployeesGridView.DataBind();
    }
    
    void EmployeesDetailsView_ItemUpdated(Object sender, DetailsViewUpdatedEventArgs e) {
        EmployeesGridView.DataBind();
    }
    
    void EmployeesDetailsView_ItemDeleted(Object sender, DetailsViewDeletedEventArgs e) {
        EmployeesGridView.DataBind();
    }
    void EmployeesGridView_OnSelectedIndexChanged(object sender, EventArgs e) {
        EmployeeDetailsObjectDataSource.SelectParameters["EmployeeID"].DefaultValue =
            EmployeesGridView.SelectedDataKey.Value.ToString();
        EmployeesDetailsView.DataBind();
    }
    void EmployeeDetailsObjectDataSource_OnInserted(object sender,
        ObjectDataSourceStatusEventArgs e) {
    
        EmployeeDetailsObjectDataSource.SelectParameters["EmployeeID"].DefaultValue =
            e.ReturnValue.ToString();
        EmployeesDetailsView.DataBind();
    }
    void EmployeeDetailsObjectDataSource_OnUpdated(object sender,
        ObjectDataSourceStatusEventArgs e) {
    
        if ((int)e.ReturnValue == 0)
            Msg.Text = "Employee was not updated. Please try again.";
    }
    void EmployeeDetailsObjectDataSource_OnDeleted(object sender,
        ObjectDataSourceStatusEventArgs e) {
    
        if ((int)e.ReturnValue == 0)
            Msg.Text = "Employee was not deleted. Please try again.";
    }
    void Page_Load() {
        Msg.Text = "";
    }
    </script>
    <html>
      <body>
        <form id="Form1" runat="server">
          <h3>ObjectDataSource Example</h3>
          <asp:Label id="Msg" runat="server" ForeColor="Red" />
          <asp:ObjectDataSource
              ID="EmployeesObjectDataSource"
              runat="server"
              TypeName="NorthwindData"
              SortParameterName="SortColumns"
              EnablePaging="true"
              SelectCountMethod="SelectCount"
              StartRowIndexParameterName="StartRecord"
              MaximumRowsParameterName="MaxRecords"
              SelectMethod="GetAllEmployees" >
          </asp:ObjectDataSource>
          <asp:ObjectDataSource
              ID="EmployeeDetailsObjectDataSource"
              runat="server"
              TypeName="NorthwindData"
              ConflictDetection="CompareAllValues"
              OldValuesParameterFormatString="{0}"
              SelectMethod="GetEmployee"
              InsertMethod="InsertEmployee"
              UpdateMethod="UpdateEmployee"
              DeleteMethod="DeleteEmployee"
              OnInserted="EmployeeDetailsObjectDataSource_OnInserted"
              OnUpdated="EmployeeDetailsObjectDataSource_OnUpdated"
              OnDeleted="EmployeeDetailsObjectDataSource_OnDeleted">
              <SelectParameters>
                  <asp:Parameter Name="EmployeeID" Type="Int32" />
              </SelectParameters>
          </asp:ObjectDataSource>
          <table cellspacing="10">
            <tr>
              <td valign="top">
                <asp:GridView ID="EmployeesGridView"
                    DataSourceID="EmployeesObjectDataSource"
                    AutoGenerateColumns="false"
                    AllowSorting="true"
                    AllowPaging="true"
                    PageSize="5"
                    DataKeyNames="EmployeeID"
                    OnSelectedIndexChanged="EmployeesGridView_OnSelectedIndexChanged"
                    RunAt="server">
                    <HeaderStyle backcolor="lightblue" forecolor="black"/>
                    <Columns>
                    <asp:ButtonField Text="Details..."
                    HeaderText="Show Details"
                    CommandName="Select"/>
    
                    <asp:BoundField DataField="EmployeeID" HeaderText="Employee ID"
                    SortExpression="EmployeeID" />
                    <asp:BoundField DataField="FirstName" HeaderText="First Name"
                    SortExpression="FirstName" />
                    <asp:BoundField DataField="LastName" HeaderText="Last Name"
                    SortExpression="LastName, FirstName" />
                    </Columns>
                </asp:GridView>
              </td>
              <td valign="top">
                <asp:DetailsView ID="EmployeesDetailsView"
                    DataSourceID="EmployeeDetailsObjectDataSource"
                    AutoGenerateRows="false"
                    EmptyDataText="No records."
                    DataKeyNames="EmployeeID"
                    Gridlines="Both"
                    AutoGenerateInsertButton="true"
                    AutoGenerateEditButton="true"
                    AutoGenerateDeleteButton="true"
                    OnItemInserted="EmployeesDetailsView_ItemInserted"
                    OnItemUpdated="EmployeesDetailsView_ItemUpdated"
                    OnItemDeleted="EmployeesDetailsView_ItemDeleted"
                    RunAt="server">
                    <HeaderStyle backcolor="Navy" forecolor="White"/>
                    <RowStyle backcolor="White"/>
                    <AlternatingRowStyle backcolor="LightGray"/>
                    <EditRowStyle backcolor="LightCyan"/>
                    <Fields>
                        <asp:BoundField DataField="EmployeeID" HeaderText="Employee ID"
                            InsertVisible="False" ReadOnly="true"/>
                        <asp:BoundField DataField="FirstName" HeaderText="First Name"/>
                        <asp:BoundField DataField="LastName" HeaderText="Last Name"/>
                        <asp:BoundField DataField="Address" HeaderText="Address"/>
                        <asp:BoundField DataField="City" HeaderText="City"/>
                        <asp:BoundField DataField="Region" HeaderText="Region"/>
                        <asp:BoundField DataField="PostalCode" HeaderText="Postal Code"/>
                    </Fields>
                  </asp:DetailsView>
                </td>
              </tr>
            </table>
          </form>
        </body>
      </html>
    
  8. Zapisz wszystkie pliki i przeglądaj object.aspx.

  9. Interakcja z interfejsem przez wyświetlanie szczegółów, edytowanie pracowników, dodawanie pracowników i usuwanie pracowników.