Опубликован: 07.05.2010 | Уровень: для всех | Доступ: платный
Лекция 13:

Привязка данных ADO.NET

Привязка DataReader к списковым элементам управления

Предыдущий пример использует в качестве источника данных класс Hashtable, потому что он реализует интерфейс

System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<TKey,TValue>>.

В качестве источника данных можно использовать любой класс, наследующий этот интерфейс. Вот некоторые из библиотечных классов, производных от интерфейсного класса ICollection:

  • System.Collections.ArrayList
  • Microsoft.VisualBasic.Collection
  • System.Collections.Hashtable
  • System.Collections.Generic.Dictionary<TKey, TValue>
  • System.Data.DataView

Учитывая, что DataReader представляет данные также в виде таблицы с именованными столбцами, мы можем так сформулировать SQL-запрос к базе данных, что в DataReader будут загружены два нужных нам столбца: один из которых можно считать Key, другой - Value. В элементе управления свойству DataTextField нужно присвоить имя поля, отображаемого в списке, а свойству DataValueField - имя поля, неотображаемого в списке.

Приведем пример. Пусть мы хотим заполнить окно списка ListBox полными именами всех сотрудников, хранящихся в таблице Employees учебной базы данных Northwind. Чтобы получить два столбца DataReader, один из которых будет вычисляемый, нужно сформулировать SQL-запрос таким образом

SELECT EmployeeID, TitleOfCourtesy + ' ' + FirstName + ' ' + LastName AS FullName FROM Employees
  • Добавьте к проекту новую страницу DataReaderListBinding.aspx с разделяемым кодом и назначьте ее стартовой
  • Оформите и настройте интерфейсную часть страницы DataReaderListBinding.aspx так, чтобы она имела следующее дескрипторное представление
    <%@ Page Language="C#" AutoEventWireup="true" 
        CodeFile="DataReaderListBinding.aspx.cs" 
        Inherits="DataReaderListBinding" %>
        
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Untitled Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:ListBox ID="ListBox1" runat="server" DataTextField="FullName" 
                DataValueField="EmployeeID" SelectionMode="Multiple" Rows="10" />
            <br />
            <br />
            <asp:Button ID="GetSelection" runat="server" Text="Получить выделенное" 
                OnClick="GetSelection_Click" />
            <br />
            <br />
            <asp:Literal ID="Result" runat="server" EnableViewState="False" />
        </div>
        </form>
    </body>
    </html>
  • Заполните файл поддержки DataReaderListBinding.aspx.cs следующим кодом
    using System;
    using System.Data;
    using System.Web.Configuration;
    using System.Data.SqlClient;
    using System.Web.UI.WebControls;
        
    public partial class DataReaderListBinding : System.Web.UI.Page
    {
        
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!this.IsPostBack)
            {
                // Создать объекты Command и Connection
                string connectionString = WebConfigurationManager.
                    ConnectionStrings["Northwind"].ConnectionString;
                string sql = "SELECT EmployeeID, "
                            + "TitleOfCourtesy + ' ' + FirstName + ' ' + LastName "
                            + "AS FullName FROM Employees";
                SqlConnection con = new SqlConnection(connectionString);
                SqlCommand cmd = new SqlCommand(sql, con);
        
                try
                {
                    // Открыть соединение и получить DataReader
                    con.Open();
                    SqlDataReader reader = cmd.ExecuteReader();
                    // Привязать DataReader к списку и заполнить список
                    ListBox1.DataSource = reader;
                    ListBox1.DataBind();
                    reader.Close();
                }
                finally
                {
                    // Закрыть соединение
                    con.Close();
                }
            }
        }
        
        protected void GetSelection_Click(object sender, EventArgs e)
        {
            Result.Text = "<b>Выделены сотрудники:</b>";
            Result.Text += "<ol>";
            foreach (ListItem item in ListBox1.Items)
                if (item.Selected)
                    Result.Text += 
                        String.Format("<li> (\"{0}\", \"{1}\")</li>", item.Text, item.Value);
            Result.Text += "</ol>";
        }
    }

Здесь мы заполнили список только при первом запросе страницы, расчитывая, что далее заполненный список будет сохраняться в состоянии вида. Если в элементе ListBox1 отключить сохранение состояния вида, установив EnableViewState="False", то при обратной отсылке список окажется пустым (попробуйте!).

  • Исполните страницу DataReaderListBinding.aspx для получения следующего результата

Выделены сотрудники:

  1. ("Dr. Andrew Fuller", "2")
  2. ("Mr. Steven Buchanan", "5")
  3. ("Ms. Anne Dodsworth", "9")

Если для визуализации данных мы хотим использовать DropDownList, CheckListBox или RadioButtonList вместо ListBox, то достаточно изменить объявление элемента управления в интерфейсной части страницы. Остальная часть кода останется прежней.

Элемент управления GridView с множественной привязкой данных

Кроме списковых элементов управления, которые можно использовать для отображения множественных данных, существуют более специализированные элементы управления, спроектированные специально для этих целей. К ним относятся GridView, DetailsView и FormView. Кроме того, механизм привязки имеют и такие элементы, как Menu, TreeView и AdRotator, хотя и служат несколько для других целей.

Здесь мы поговорим об элементе управления GridView, возможных способах его настройки и привязки к нему разных источников данных. Как и списковые элементы управления, GridView имеет свойство DataSource и метод DataBind(). Типовое объявление элемента GridView в интерфейсной части страницы выглядит так:

<asp:GridView ID="GridView1" runat="server" />

Рассмотрим пример, в котором данные DataReader будут привязываться не к списковому элементу управления, а к GridView.

  • Создайте новую страницу GridViewDataBind.aspx с разделяемым кодом и назначьте ее стартовой
  • Поместите на страницу из вкладки Data панели Toolbox элемент управления GridView
  • Откройте на редактирование файл GridViewDataBind.aspx.cs и заполните его следующим кодом
    using System;
    using System.Data;
    using System.Web.Configuration;
    using System.Data.SqlClient;
    using System.Web.UI.WebControls;
        
    public partial class DataReaderListBinding : System.Web.UI.Page
    {
        
        protected void Page_Load(object sender, EventArgs e)
        {
            // Создать объекты Command и Connection
            string connectionString = WebConfigurationManager.
                ConnectionStrings["Northwind"].ConnectionString;
            string sql = "SELECT EmployeeID, FirstName, LastName, "
                        + "Title, City FROM Employees";
            SqlConnection con = new SqlConnection(connectionString);
            SqlCommand cmd = new SqlCommand(sql, con);
        
            try
            {
                // Открыть соединение и получить DataReader
                con.Open();
                SqlDataReader reader = cmd.ExecuteReader();
                // Привязать DataReader к GridView
                GridView1.DataSource = reader;
                GridView1.DataBind();
                reader.Close();
            }
            finally
            {
                // Закрыть соединение
                con.Close();
            }
        }
    }
  • Исполните страницу GridViewDataBind.aspx для получения следующего результат
EmployeeID FirstName LastName Title City
1 Nancy Davolio Sales Representative Redmond
2 Andrew Fuller Vice President, Sales Tacoma
3 Janet Leverling Sales Representative Kirkland
4 Margaret Peacock Sales Representative Redmond
5 Steven Buchanan Sales Manager London
6 Michael Suyama Sales Representative London
7 Robert King Sales Representative London
8 Laura Callahan Inside Sales Coordinator Redmond
9 Anne Dodsworth Sales Representative London

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

В библиотеке .NET Framework имеется ряд классов, которые соединяются с любым поставщиком данных ADO.NET, облегчая привязку данных к элементам отображения. Они называются источниками данных и реализуют интерфейс IDataSource.


К источникам данных относятся следующие классы:

  • System.Web.UI.WebControls.ObjectDataSource - позволяет подключиться к пользовательскому классу доступа к данным
  • System.Web.UI.WebControls.SqlDataSource - позволяет подключиться к любому поставщику ADO.NET
  • System.Web.UI.WebControls.SiteMapDataSource - позволяет подключиться к файлу System.Web.SiteMap, описывающему навигационную структуру Web-сайта
  • System.Web.UI.WebControls.XmlDataSource - позволяет подключиться к XML-файлу

Все эти классы представлены как элементы управления на вкладке Data панели Toolbox оболочки Visual Studio 2005 и являются новшеством библиотеки .NET Framework 2.0. Если перенести этот элемент на страницу, то он отображается серым цветом как невизуальный компонент страницы. В то же время в разметочной части страницы появляется соответствующий дескриптор элемента управления.

Источники данных используют поставщики данных для подключения и обмена данными с базой данных. Но используют они их в обобщенном виде через фабрики поставщиков, которые находятся в пространствах имен

  • System.Data.Common
  • System.Data.SqlClient
  • System.Data.OracleClient
  • System.Data.OleDb
  • System.Data.Odbc

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

Чтобы манипулировать данными одной конкретной таблицы базы данных, требуется создать для нее свой источник данных. Две таблицы, даже если они связаны отношением, должны иметь каждая по своему отдельному источнику данных. Не отображаемый на странице источник данных нужно конфигурировать (настроить) на соединение со своей таблицей. Это делается через атрибуты дескриптора напрямую или через свойства в панели Properties. В настройках обязательно следует указать

  • строку соединения ConnectionString
  • имя фабрики поставщиков ProviderName
  • тип SQL-команды (встроенная SQL-команда Text или хранимая процедура StoredProcedure ) в свойствах SelectCommandType, InsertCommandType, UpdateCommandType и DeleteCommandType
  • саму SQL-команду или имя хранимой процедуры в свойствах SelectQuery, InsertQuery, UpdateQuery и DeleteQuery (Такие имена имеют свойства в панели Properties, которые в дескрипторном представлении источника данных трансформируются в имена атрибутов SelectCommand, InsertCommand, UpdateCommand и DeleteCommand )

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

Строку соединения можно жестко указать в свойствах источника данных, но лучше читать из файла web.config, используя $ - выражение привязки данных.

Приведем пример дескриптора сконфигурированного источника данных, который извлекает записи из таблицы Employees учебной базы данных Northwind.

<asp:SqlDataSource ID="SqlDataSource1" runat="server" 
    ProviderName="System.Data.SqlClient" 
    ConnectionString="<%$ connectionStrings:Northwind %>" 
    SelectCommand=
    "SELECT EmployeeID, FirstName, LastName, Title, City FROM Employees" />

Источник данных можно сконфигурировать и с помощью мастера, вызвав его командой Configure Data Source встроенного меню

Создав и настроив источник данных, мы получаем возможность привязать к нему любой элемент отображения данных: HtmlSelect, ListBox, DropDownList, CheckBoxList, RadioButtonList, BulletedList уже на этапе проектирования, не написав ни одной строки кода в обработчике Page_Load(). Более того, если выполнить команду Refresh Scheme встроенной панели источника данных, то он одноразово соединится с базой данных и заполнится требуемой информацией, которую потом можно выбирать из раскрывающихся списков при настройке привязываемых к нему элементов отображения данных. Если мы используем источник данных, то создавать соединение, объекты команд и вызывать метод Page.DataBind() в коде страницы для заполнения элементов отображения, не нужно - все будет выполняться автоматически при запуске страницы.

  • Создайте страницу с объединенным кодом и именем SqlDataSourceSimple.aspx. Назначьте ее стартовой
  • Из вкладки Data панели Toolbox добавьте на страницу неотображаемый элемент управления SqlDataSource, через который мы привяжем данные к элементу отображения
  • Из вкладки Standard панели Toolbox добавьте на страницу элемент управления ListBox
  • Из вкладки Data панели Toolbox добавьте на страницу элемент управления GridView
  • Из вкладки Standard панели Toolbox добавьте на страницу элемент управления Button
  • Настройте объекты страницы: источник данных SqlDataSource1, элемент отображения данных ListBox1, многофункциональный элемент отображения данных GridView1, кнопку обратной отсылки Button1 следующим образом
    <%@ Page Language="C#" %>
        
    <script runat="server">
        // Здесь мы не написали ни строчки кода!!!
    </script>
        
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Untitled Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
                ProviderName="System.Data.SqlClient" 
                ConnectionString="<%$ connectionStrings:Northwind %>" 
                SelectCommand=
                "SELECT EmployeeID, FirstName, LastName, Title, City FROM Employees" />
            <asp:ListBox ID="ListBox1" runat="server" DataSourceID="SqlDataSource1"
                DataTextField="FirstName" />
            <br />
            <br />
            <asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" />
            <br />
            <asp:Button ID="Button1" runat="server" Text="Обновить" /></div>
        </form>
    </body>
    </html>
  • Исполните страницу SqlDataSourceSimple.aspx, чтобы получить следующий результат

EmployeeID FirstName LastName Title City
1 Nancy Davolio Sales Representative Redmond
2 Andrew Fuller Vice President, Sales Tacoma
3 Janet Leverling Sales Representative Kirkland
4 Margaret Peacock Sales Representative Redmond
5 Steven Buchanan Sales Manager London
6 Michael Suyama Sales Representative London
7 Robert King Sales Representative London
8 Laura Callahan Inside Sales Coordinator Redmond
9 Anne Dodsworth Sales Representative London

Все работает автоматически без необходимости написания кода (который нам тоже не страшен). Привязка данных при каждой обратной отсылке повторяется заново, и в этом есть некоторый недостаток, поскольку каждый раз должно создаваться соединение с базой данных и производиться выборка данных. К счастью, разработчики ASP.NET 2.0 устранили этот недостаток за счет автоматического кэширования данных источником SqlDataSource на случай, если данные изменяются редко.

Если изменить свойство DataSourceMode источника данных с DataSet (установлено по умолчанию) на DataReader и исполнить страницу, то в данном случае получим тот же самый результат. Режим DataSourceMode=DataSet работы источника данных почти всегда лучше, чем режим DataSourceMode=DataReader, поскольку он поддерживает расширенную сортировку, фильтрацию и настройку кэширования, имеющиеся в DataSet. Однако, если стоит задача отображать большие экранные таблицы, то лучше использовать режим DataSourceMode=DataReader, потому что он более эффективно использует память сервера.

Илья Онучин
Илья Онучин
Россия
Igor Chelyadinski
Igor Chelyadinski
Беларусь, Минск, №54, 2013