Элементы управления источником данных

от Корпорации Майкрософт

Элемент управления DataGrid в ASP.NET 1.x значительно улучшил доступ к данным в веб-приложениях. Тем не менее, это было не так удобно, как это могло бы быть. По-прежнему требуется значительный объем кода, чтобы получить от него много полезных функций. Такова модель во всех попытках доступа к данным в версии 1.x.

Элемент управления DataGrid в ASP.NET 1.x значительно улучшил доступ к данным в веб-приложениях. Тем не менее, это было не так удобно, как это могло бы быть. По-прежнему требуется значительный объем кода, чтобы получить от него много полезных функций. Такова модель во всех попытках доступа к данным в версии 1.x.

ASP.NET 2.0 устраняет это частично с помощью элементов управления источником данных. Элементы управления источником данных в ASP.NET 2.0 предоставляют разработчикам декларативную модель для получения данных, отображения и редактирования данных. Цель элементов управления источником данных — обеспечить согласованное представление данных элементам управления с привязкой к данным независимо от источника этих данных. В основе элементов управления источником данных в ASP.NET 2.0 лежит абстрактный класс DataSourceControl. Класс DataSourceControl предоставляет базовую реализацию интерфейсов IDataSource и IListSource, последний из которых позволяет назначить элемент управления источником данных в качестве источника данных элемента управления с привязкой к данным (с помощью нового свойства DataSourceId, описанного далее) и предоставить данные в нем в виде списка. Каждый список данных из элемента управления источником данных предоставляется в виде объекта DataSourceView. Доступ к экземплярам DataSourceView предоставляется интерфейсом IDataSource. Например, метод GetViewNames возвращает ICollection, который позволяет перечислить DataSourceViews, связанные с определенным элементом управления источником данных, а метод GetView позволяет получить доступ к определенному экземпляру DataSourceView по имени.

Элементы управления источником данных не имеют пользовательского интерфейса. Они реализуются как серверные элементы управления, чтобы поддерживать декларативный синтаксис и при необходимости иметь доступ к состоянию страницы. Элементы управления источником данных не отображают html-разметку для клиента.

Примечание

Как вы увидите позже, есть также преимущества кэширования, получаемые с помощью элементов управления источником данных.

Хранение строк подключения

Прежде чем приступить к рассмотрению настройки элементов управления источником данных, в ASP.NET 2.0 мы рассмотрим новую возможность, касающуюся строк подключения. ASP.NET 2.0 представляет новый раздел в файле конфигурации, который позволяет легко хранить строки подключения, которые можно считывать динамически во время выполнения. Раздел <connectionStrings> упрощает хранение строк подключения.

В приведенном ниже фрагменте кода добавляется новая строка подключения.

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

Примечание

Как и в случае с разделом appSettings>, <раздел connectionStrings> отображается вне <раздела system.web> в файле конфигурации<.

Чтобы использовать эту строку подключения, при задании атрибута ConnectionString серверного элемента управления можно использовать следующий синтаксис.

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

Раздел <connectionStrings> также можно зашифровать, чтобы конфиденциальные сведения не предоставлялись. Эта возможность будет описана в следующем модуле.

Кэширование источников данных

Каждый элемент DataSourceControl предоставляет четыре свойства для настройки кэширования; EnableCaching, CacheDuration, CacheExpirationPolicy и CacheKeyDependency.

EnableCaching

EnableCaching — это логическое свойство, которое определяет, включено ли кэширование для элемента управления источником данных.

Свойство CacheDuration

Свойство CacheDuration задает количество секунд, в течение которых кэш остается действительным. Если задать для этого свойства значение 0 , кэш остается действительным до тех пор, пока он явно не будет признан недействительным.

Свойство CacheExpirationPolicy

Для свойства CacheExpirationPolicy можно задать значение AbsoluteилиСкользящий. Присвоить ему значение Absolute означает, что максимальное время кэширования данных — это количество секунд, заданное свойством CacheDuration. Если задать для него значение Скользящее, время истечения срока действия сбрасывается при выполнении каждой операции.

Свойство CacheKeyDependency

Если для свойства CacheKeyDependency указано строковое значение, ASP.NET настроит новую зависимость кэша на основе этой строки. Это позволяет явно сделать кэш недействительным, просто изменив или удалив элемент CacheKeyDependency.

Важно! Если олицетворение включено и доступ к источнику данных и (или) содержимому данных основан на идентификаторе клиента, рекомендуется отключить кэширование, установив для параметра EnableCaching значение False. Если кэширование включено в этом сценарии и пользователь, отличный от пользователя, который первоначально запросил данные, отправляет запрос, авторизация для источника данных не применяется. Данные будут просто обслуживаться из кэша.

Элемент управления SqlDataSource

Элемент управления SqlDataSource позволяет разработчику получать доступ к данным, хранящимся в любой реляционной базе данных, поддерживающей ADO.NET. Он может использовать поставщик System.Data.SqlClient для доступа к базе данных SQL Server, поставщик System.Data.OleDb, поставщик System.Data.Odbc или поставщик System.Data.OracleClient для доступа к Oracle. Таким образом, SqlDataSource, безусловно, используется не только для доступа к данным в базе данных SQL Server.

Чтобы использовать SqlDataSource, необходимо просто указать значение для свойства ConnectionString и указать команду SQL или хранимую процедуру. Элемент управления SqlDataSource отвечает за работу с базовой архитектурой ADO.NET. Он открывает подключение, запрашивает источник данных или выполняет хранимую процедуру, возвращает данные, а затем закрывает подключение для вас.

Примечание

Так как класс DataSourceControl автоматически закрывает подключение, он должен уменьшить количество вызовов клиентов, создаваемых утечкой подключения к базе данных.

Приведенный ниже фрагмент кода привязывает элемент управления DropDownList к элементу управления SqlDataSource с помощью строки подключения, хранящейся в файле конфигурации, как показано выше.

<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>

Как показано выше, свойство DataSourceMode sqlDataSource задает режим для источника данных. В приведенном выше примере dataSourceMode имеет значение DataReader. В этом случае SqlDataSource вернет объект IDataReader с помощью курсора только для чтения и пересылки. Заданный тип возвращаемого объекта управляется используемым поставщиком. В этом случае я использую поставщик System.Data.SqlClient, как указано в <разделе connectionStrings> файла web.config. Таким образом, возвращаемый объект будет иметь тип SqlDataReader. Указав значение DataSourceMode dataSet, данные можно сохранить в DataSet на сервере. Этот режим позволяет добавлять такие функции, как сортировка, разбиение по страницам и т. д. Если бы я привязывал SqlDataSource к элементу управления GridView, я бы выбрал режим DataSet. Однако в случае с DropDownList правильным выбором является режим DataReader.

Примечание

При кэшировании SqlDataSource или AccessDataSource свойство DataSourceMode должно иметь значение DataSet. Исключение возникнет, если включить кэширование с dataSourceMode DataReader.

Свойства SqlDataSource

Ниже приведены некоторые свойства элемента управления SqlDataSource.

CancelSelectOnNullParameter

Логическое значение, указывающее, отменена ли команда select, если один из параметров имеет значение NULL. По умолчанию имеет значение TRUE.

ConflictDetection

В ситуации, когда несколько пользователей могут одновременно обновлять источник данных, свойство ConflictDetection определяет поведение элемента управления SqlDataSource. Это свойство вычисляется как одно из значений перечисления ConflictOptions. Это значения CompareAllValues и OverwriteChanges. Если задано значение OverwriteChanges, последний пользователь, записывший данные в источник данных, перезаписывает все предыдущие изменения. Однако если свойству ConflictDetection присвоено значение CompareAllValues, параметры создаются для столбцов, возвращаемых Командой SelectCommand, а параметры также создаются для хранения исходных значений в каждом из этих столбцов, что позволяет SqlDataSource определить, изменились ли значения с момента выполнения SelectCommand.

DeleteCommand

Задает или возвращает строку SQL, используемую при удалении строк из базы данных. Это может быть SQL-запрос или имя хранимой процедуры.

DeleteCommandType

Задает или получает тип команды удаления: SQL-запрос (текст) или хранимую процедуру (StoredProcedure).

DeleteParameters

Возвращает параметры, используемые командой DeleteCommand объекта SqlDataSourceView, связанного с элементом управления SqlDataSource.

OldValuesParameterFormatString

Это свойство используется для указания формата исходных параметров значений в случаях, когда свойству ConflictDetection присвоено значение CompareAllValues. Значение по умолчанию — это {0} означает, что исходные параметры значений будут принимать то же имя, что и исходный параметр. Иными словами, если имя поля — EmployeeID, исходный параметр значения будет иметь значение @EmployeeID.

SelectCommand

Задает или возвращает строку SQL, используемую для получения данных из базы данных. Это может быть SQL-запрос или имя хранимой процедуры.

SelectCommandType

Задает или получает тип команды select, sql-запрос (текст) или хранимую процедуру (StoredProcedure).

Selectparameters

Возвращает параметры, используемые командой SelectCommand объекта SqlDataSourceView, связанного с элементом управления SqlDataSource.

SortParameterName

Возвращает или задает имя параметра хранимой процедуры, используемого при сортировке данных, полученных элементом управления источником данных. Допустимо, только если для параметра SelectCommandType задано значение StoredProcedure.

SqlCacheDependency

Строка с разделителями с запятой, указывающая базы данных и таблицы, используемые в зависимости кэша SQL Server. (Зависимости кэша SQL будут рассмотрены в следующем модуле.)

UpdateCommand

Задает или возвращает строку SQL, используемую при обновлении данных в базе данных. Это может быть SQL-запрос или имя хранимой процедуры.

UpdateCommandType

Задает или получает тип команды обновления, sql-запрос (текст) или хранимую процедуру (StoredProcedure).

UpdateParameters

Возвращает параметры, используемые командой UpdateCommand объекта SqlDataSourceView, связанного с элементом управления SqlDataSource.

Элемент управления AccessDataSource

Элемент управления AccessDataSource является производным от класса SqlDataSource и используется для привязки данных к базе данных Microsoft Access. Свойство ConnectionString для элемента управления AccessDataSource является свойством только для чтения. Вместо использования свойства ConnectionString свойство DataFile используется для указания на базу данных Access, как показано ниже.

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

AccessDataSource всегда устанавливает для параметра ProviderName базового SqlDataSource значение System.Data.OleDb и подключается к базе данных с помощью поставщика OLE DB Microsoft.Jet.OLEDB.4.0. Вы не можете использовать элемент управления AccessDataSource для подключения к защищенной паролем базе данных Access. Если необходимо подключиться к защищенной паролем базе данных, следует использовать элемент управления SqlDataSource.

Примечание

Базы данных Access, хранящиеся на веб-сайте, должны размещаться в каталоге App_Data. ASP.NET не позволяет просматривать файлы в этом каталоге. При использовании баз данных Access необходимо предоставить учетной записи процесса разрешения на чтение и запись в каталоге App_Data.

Элемент управления XmlDataSource

XmlDataSource используется для привязки XML-данных к элементам управления с привязкой к данным. Вы можете выполнить привязку к XML-файлу с помощью свойства DataFile или выполнить привязку к XML-строке с помощью свойства Data. XmlDataSource предоставляет атрибуты XML в качестве привязываемых полей. В случаях, когда необходимо выполнить привязку к значениям, которые не представлены в виде атрибутов, необходимо использовать XSL-преобразование. Выражения XPath также можно использовать для фильтрации XML-данных.

Рассмотрим следующий 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>

Обратите внимание, что XmlDataSource использует свойство XPath Люди/Person для фильтрации только по узлам <Person>. Затем DropDownList привязывает данные к атрибуту LastName с помощью свойства DataTextField.

Хотя элемент управления XmlDataSource в основном используется для привязки данных к XML-данным, предназначенным только для чтения, можно изменить XML-файл данных. Обратите внимание, что в таких случаях автоматическая вставка, обновление и удаление сведений в XML-файле не выполняется автоматически, как в других элементах управления источником данных. Вместо этого необходимо написать код для ручного редактирования данных с помощью следующих методов элемента управления XmlDataSource.

GetXmlDocument

Извлекает объект XmlDocument, содержащий XML-код, полученный xmlDataSource.

Сохранить

Сохраняет xmlDocument в памяти обратно в источник данных.

Важно понимать, что метод Save будет работать только при выполнении следующих двух условий:

  1. XmlDataSource использует свойство DataFile для привязки к XML-файлу вместо свойства Data для привязки к XML-данным в памяти.
  2. Преобразование не указывается с помощью свойства Transform или TransformFile.

Обратите также внимание, что метод Save может давать непредвиденные результаты при одновременном вызове несколькими пользователями.

Элемент управления ObjectDataSource

Элементы управления источником данных, которые мы рассмотрели до этого момента, отлично подходят для двухуровневых приложений, в которых система управления источником данных напрямую взаимодействует с хранилищем данных. Однако многие реальные приложения являются многоуровневыми приложениями, в которых системе управления источником данных может потребоваться взаимодействие с бизнес-объектом, который, в свою очередь, взаимодействует с уровнем данных. В таких ситуациях ObjectDataSource хорошо заполняет счет. Объект ObjectDataSource работает в сочетании с исходным объектом. Элемент управления ObjectDataSource создаст экземпляр исходного объекта, вызовет указанный метод и удаляет экземпляр объекта в область одного запроса, если объект имеет методы экземпляра вместо статических методов (общий доступ в Visual Basic). Таким образом, объект должен быть без отслеживания состояния. То есть объект должен получить и освободить все необходимые ресурсы в пределах одного запроса. Вы можете управлять созданием исходного объекта, обрабатывая событие ObjectCreating элемента управления ObjectDataSource. Можно создать экземпляр исходного объекта, а затем задать для свойства ObjectInstance класса ObjectDataSourceEventArgs значение этого экземпляра. Элемент управления ObjectDataSource будет использовать экземпляр, созданный в событии ObjectCreating, а не создавать экземпляр самостоятельно.

Если исходный объект для элемента управления ObjectDataSource предоставляет общедоступные статические методы (общие в Visual Basic), которые можно вызывать для извлечения и изменения данных, элемент управления ObjectDataSource вызывает эти методы напрямую. Если элемент управления ObjectDataSource должен создать экземпляр исходного объекта для выполнения вызовов методов, объект должен включать открытый конструктор, который не принимает параметров. Элемент управления ObjectDataSource вызывает этот конструктор при создании нового экземпляра исходного объекта.

Если исходный объект не содержит открытый конструктор без параметров, можно создать экземпляр исходного объекта, который будет использоваться элементом управления ObjectDataSource в событии ObjectCreating.

Указание методов объекта

Исходный объект для элемента управления ObjectDataSource может содержать любое количество методов, используемых для выбора, вставки, обновления или удаления данных. Эти методы вызываются элементом управления ObjectDataSource на основе имени метода, определяемого с помощью свойства SelectMethod, InsertMethod, UpdateMethod или DeleteMethod элемента управления ObjectDataSource. Исходный объект также может содержать необязательный метод SelectCount, который определяется элементом управления ObjectDataSource с помощью свойства SelectCountMethod, возвращающего общее количество объектов в источнике данных. Элемент управления ObjectDataSource вызывает метод SelectCount после вызова метода Select, чтобы получить общее количество записей в источнике данных для использования при разбиении по страницам.

Лабораторная работа с элементами управления источником данных

Упражнение 1. Отображение данных с помощью элемента управления SqlDataSource

В следующем упражнении для подключения к базе данных Northwind используется элемент управления SqlDataSource. Предполагается, что у вас есть доступ к базе данных Northwind на экземпляре SQL Server 2000.

  1. Создание нового веб-сайта ASP.NET.

  2. Добавьте новый файл web.config.

    1. Щелкните правой кнопкой мыши проект в Обозреватель решений и выберите команду Добавить новый элемент.
    2. Выберите Файл веб-конфигурации в списке шаблонов и нажмите кнопку Добавить.
  3. Измените <раздел connectionStrings> следующим образом:

    <asp:SqlDataSource ID="SqlDataSource1" runat="server"
        ConnectionString="<%$ConnectionStrings:Northwind%>"
        SelectCommand="SELECT * FROM Products">
    </asp:SqlDataSource>
    
  4. Перейдите в представление кода и добавьте атрибуты ConnectionString и SelectCommand в <элемент управления asp:SqlDataSource> следующим образом:

    <asp:SqlDataSource ID="SqlDataSource1" runat="server"
        ConnectionString="<%$ConnectionStrings:Northwind%>"
        SelectCommand="SELECT * FROM Products">
    </asp:SqlDataSource>
    
  5. В режиме конструктора добавьте новый элемент управления GridView.

  6. В раскрывающемся списке Выбор источника данных в меню Задачи GridView выберите SqlDataSource1.

  7. Щелкните правой кнопкой мыши Default.aspx и выберите в меню Пункт Просмотр в браузере. Нажмите кнопку Да при появлении запроса на сохранение.

  8. GridView отображает данные из таблицы Products.

Упражнение 2. Изменение данных с помощью элемента управления SqlDataSource

В следующем упражнении показано, как привязать данные к элементу управления DropDownList с помощью декларативного синтаксиса и изменить данные, представленные в элементе управления DropDownList.

  1. В режиме конструктора удалите элемент управления GridView из default.aspx.

    Важно! Оставьте элемент управления SqlDataSource на странице.

  2. Добавьте элемент управления DropDownList в Default.aspx.

  3. Переключитесь в представление источника.

  4. Добавьте атрибуты DataSourceId, DataTextField и DataValueField в <элемент управления asp:DropDownList> следующим образом:

    <asp:DropDownList ID="ddlProducts" runat="server"
         DataSourceId="SqlDataSource1" DataTextField="ProductName"
         DataValueField="ProductID">
    </asp:DropDownList>
    
  5. Сохраните Файл Default.aspx и просмотрите его в браузере. Обратите внимание, что DropDownList содержит все продукты из базы данных Northwind.

  6. Закройте браузер.

  7. В представлении источника Default.aspx добавьте новый элемент управления TextBox под элементом управления DropDownList. Измените свойство ID элемента TextBox на txtProductName.

  8. В элементе управления TextBox добавьте новый элемент управления Кнопка. Измените свойство ID элемента Button на btnUpdate, а свойство Text — на Обновить название продукта.

  9. В исходном представлении Default.aspx добавьте свойство UpdateCommand и два новых элемента UpdateParameters в тег SqlDataSource, как показано ниже.

    <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>
    

    Примечание

    Обратите внимание, что в этот код добавлены два параметра обновления (ProductName и ProductID). Эти параметры сопоставляются со свойством Text элемента txtProductName TextBox и свойством SelectedValue объекта ddlProducts DropDownList.

  10. Перейдите в режим конструктора и дважды щелкните элемент управления Кнопка, чтобы добавить обработчик событий.

  11. Добавьте следующий код в код btnUpdate_Click:

    SqlDataSource1.Update();
    
  12. Щелкните правой кнопкой мыши Default.aspx и выберите для просмотра его в браузере. При появлении запроса на сохранение всех изменений нажмите кнопку Да.

  13. ASP.NET разделяемые классы версии 2.0 позволяют выполнять компиляцию во время выполнения. Нет необходимости создавать приложение, чтобы изменения в коде вступили в силу.

  14. Выберите продукт из раскрывающегося списка.

  15. Введите новое имя выбранного продукта в поле TextBox и нажмите кнопку Обновить.

  16. Имя продукта обновляется в базе данных.

Упражнение 3. Использование элемента управления ObjectDataSource

В этом упражнении показано, как использовать элемент управления ObjectDataSource и исходный объект для взаимодействия с базой данных Northwind.

  1. Щелкните правой кнопкой мыши проект в Обозреватель решений и выберите команду Добавить новый элемент.

  2. Выберите Веб-форма в списке шаблонов. Измените имя на object.aspx и нажмите кнопку Добавить.

  3. Щелкните правой кнопкой мыши проект в Обозреватель решений и выберите команду Добавить новый элемент.

  4. Выберите Класс в списке шаблонов. Измените имя класса на NorthwindData.cs и нажмите кнопку Добавить.

  5. Нажмите кнопку Да при появлении запроса на добавление класса в папку App_Code.

  6. Добавьте следующий код в файл 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. Добавьте следующий код в представление Source объекта 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. Сохраните все файлы и просмотрите object.aspx.

  9. Взаимодействуйте с интерфейсом, просматривая сведения, изменяя сотрудников, добавляя сотрудников и удаляя сотрудников.