Udostępnij za pośrednictwem


Kontrolki źródła danych

autor: Microsoft

Kontrolka DataGrid w ASP.NET 1.x oznaczyła doskonałą 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 doskonałą 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 rozwiązuje ten problem częściowo z kontrolkami źródła danych. Kontrolki źródła danych w 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 kontroli ź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 później) i uwidocznienie danych na liście. Każda lista danych z kontrolki źródła danych jest uwidoczniona jako obiekt DataSourceView. Dostęp do wystąpień elementu DataSourceView jest udostępniany przez interfejs IDataSource. Na przykład metoda GetViewNames zwraca klasę ICollection, która umożliwia wyliczanie 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

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

Przechowywanie parametrów połączenia

Zanim przyjrzymy się sposobom 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

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ż szyfrowana, aby poufne informacje nie są uwidocznione. 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 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 określa liczbę sekund, w których pamięć podręczna pozostaje prawidłowa. Ustawienie tej właściwości na wartość 0 powoduje, że pamięć podręczna pozostanie prawidłowa do momentu jawnego unieważnienia.

CacheExpirationPolicy, właściwość

Właściwość CacheExpirationPolicy można ustawić na wartość 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.

CacheKeyDependency, właściwość

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 personifikacja jest włączona, 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 obsługiwane 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 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 SQL Server.

Aby użyć obiektu 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.

Uwaga

Ponieważ klasa DataSourceControl automatycznie zamyka połączenie, powinna zmniejszyć liczbę wywołań klientów generowanych przez wyciek Połączenia 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 elementu SqlDataSource określa tryb źródła danych. W powyższym przykładzie element DataSourceMode jest ustawiony na Wartość DataReader. W takim przypadku źródło SqlDataSource zwróci obiekt IDataReader przy użyciu kursora tylko do przodu i tylko 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 określonego <w sekcji connectionStrings> pliku web.config. W związku z tym zwracany obiekt będzie typu SqlDataReader. Określając wartość DataSourceMode zestawu danych, 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 DataSet. Jednak w przypadku listy rozwijanej tryb DataReader jest prawidłowym wyborem.

Uwaga

W przypadku buforowania elementu SqlDataSource lub accessDataSource właściwość DataSourceMode musi być ustawiona na Wartość DataSet. W przypadku włączenia buforowania za pomocą elementu DataSourceMode elementu DataReader wystąpi wyjątek.

Właściwości obiektu SqlDataSource

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

CancelSelectOnNullParameter

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

Conflictdetection

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ść oblicza jedną z wartości wyliczenia ConflictOptions. Te wartości to CompareAllValues i OverwriteChanges. Jeśli ustawiono wartość OverwriteChanges, ostatnia osoba zapisująca dane w źródle danych zastępuje wszelkie poprzednie zmiany. Jeśli jednak właściwość ConflictDetection jest ustawiona na Wartość 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 umożliwia usłudze SqlDataSource określenie, 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 delete, zapytanie SQL (tekst) lub procedurę składowaną (StoredProcedure).

Deleteparameters

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 pozycjęPolecenia

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

Selectparameters

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

Sortparametername

Pobiera lub ustawia nazwę parametru procedury składowanej, który jest używany 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 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.

Kontrola 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ę Dostawcy bazowej bazy SqlDataSource na System.Data.OleDb i łączy się z bazą danych przy użyciu dostawcy OLE DB Microsoft.Jet.OLEDB.4.0. Nie można użyć kontrolki AccessDataSource do nawiązania połączenia 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

Bazy danych dostępu przechowywane w witrynie sieci Web powinny zostać umieszczone w katalogu App_Data. ASP.NET nie zezwala na przeglądanie plików w tym katalogu. Podczas korzystania z baz danych programu Access należy przyznać kontu procesu uprawnienia odczyt i zapis do katalogu App_Data.

Kontrolka XmlDataSource

Źródło XmlDataSource służy do tworzenia powiązania danych XML z kontrolkami powiązanymi z danymi. Można powiązać z plikiem XML 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żmy 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 Osoby/Person w celu filtrowania tylko <węzłów osoby>. Właściwość DropDownList następnie data-binds z atrybutem LastName przy użyciu właściwości DataTextField.

Kontrolka XmlDataSource jest używana głównie do powiązania danych z danymi XML tylko do odczytu, ale można edytować plik danych 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 Danych Xml.

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 przynieść nieoczekiwane wyniki, gdy jest wywoływana przez wielu użytkowników jednocześnie.

Kontrolka ObjectDataSource

Kontrolki źródła danych omówione do tego momentu są doskonałym wyborem w przypadku aplikacji dwuwarstwowych, w których kontrola źródła danych komunikuje się bezpośrednio z magazynem danych. Jednak wiele rzeczywistych aplikacji to aplikacje wielowarstwowe, 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 wypełnia rachunek ładnie. 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 uzyskać i zwolnić wszystkie wymagane zasoby w ramach 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 we zdarzeniu ObjectCreating zamiast tworzyć własne wystąpienie.

Jeśli obiekt źródłowy kontrolki ObjectDataSource uwidacznia publiczne metody statyczne (udostępnione w języku Visual Basic), które można wywołać w celu pobrania i zmodyfikowania 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 liczbę wszystkich 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. Przyjęto założenie, że masz dostęp do bazy danych Northwind w wystąpieniu SQL Server 2000.

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

  2. Dodaj nowy plik web.config.

    1. Kliknij prawym przyciskiem myszy projekt w Eksplorator 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 GridView wybierz pozycję SqlDataSource1.

  7. Kliknij prawym przyciskiem myszy pozycję Default.aspx i wybierz polecenie 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 pliku Default.aspx.

    Ważne: pozostaw kontrolkę SqlDataSource na stronie.

  2. Dodaj kontrolkę DropDownList do pliku 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 plik 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 Source kontrolki Default.aspx dodaj nową kontrolkę TextBox poniżej kontrolki DropDownList. Zmień właściwość ID kontrolki TextBox na txtProductName.

  8. W obszarze kontrolki 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 Source elementu 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

    Należy pamiętać, że w tym kodzie dodano dwa parametry aktualizacji (ProductName i ProductID). Te parametry są mapowane na właściwość Text txtProductName TextBox i właściwość SelectedValue 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 pozycję Default.aspx i wybierz, aby wyświetlić go w przeglądarce. Po wyświetleniu monitu kliknij przycisk Tak, aby zapisać wszystkie zmiany.

  13. ASP.NET klasy częściowe w wersji 2.0 umożliwiają kompilację w czasie wykonywania. Nie jest konieczne skompilowanie aplikacji, aby zobaczyć, że zmiany kodu zaczęły obowiązywać.

  14. Wybierz produkt z listy rozwijanej.

  15. Wprowadź nową nazwę wybranego produktu w polu TextBox, 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 Eksplorator rozwiązań i kliknij pozycję 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 Eksplorator rozwiązań i kliknij pozycję 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 kliknij przycisk Tak, aby dodać klasę do folderu App_Code.

  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 plik object.aspx.

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