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

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

Использование ObjectDataSource для вставки и удаления записей

Аналогичным образом можно задействовать и другие оставшиеся методы нашего пользовательского класса EmployeeDB, имеющие параметры:

  • public int InsertEmployee(EmployeeDetails emp) {...}
  • public void DeleteEmployee(int employeeID) {...}

Рассмотрим операцию вставки с применением пользовательского класса EmployeeDB. Эту операцию мы вправе добавить на страницу в дополнение к уже реализованной операции обновления. Особенность реализации метода вставки состоит в том, что он возвращает значение, указывающее содержимое поля EmployeeID. Это поле в таблице является ключевым и имеет свойство AutoIncrement (автоматическое увеличение). Его значение, возвращенное методом, можно проигнорировать, но можно и перехватывать и использовать для каких-нибудь целей, например извещения пользователя.

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

  • Создайте копию страницы ObjectDataSourceUpdates2.aspx с именем ObjectDataSourceFull.aspx и назначьте ее стартовой
  • Проверьте работоспособность начального варианта страницы ObjectDataSourceFull.aspx

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

  • Добавьте после элемента GridView1 компонент LinkButton и создайте для него обработчик LinkButton1_Click()
  • В режиме Design двойным щелчком на свободном месте Web-формы создайте обработчик Page_Load() страницы, в котором мы будем формировать сообщение о номере добавленной в таблицу записи
  • Поместите после элемента LinkButton1 компонент Label с именем lblInfo, в котором мы будем размещать сообщения для пользователя о добавленной или удаленной записи таблицы Employees
  • В режиме Design вызовите встроенную панель источника ObjectDataSource1 и щелчком на ссылке Configure Data Source вызовите мастер конфигурации источника данных. Проверьте правильность подключения методов во вкладках SELECT и UPDATE, затем подключите метод удаления во вкладке DELETE
  • После щелчка на кнопке Finish откажитесь от предложения скорректировать объект GridView1
  • Вызовите через свойство ObjectDataSource1.DeleteParameters окно визуального редактирования параметров команды удаления и настройте его так
  • Выделите элемент ObjectDataSource1 и через панель Properties создайте обработчик ObjectDataSource1_Deleting() для события Deleting, в котором мы будем перехватывать номер удаляемой из таблицы записи

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

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    TypeName="EmployeeDB" SelectMethod="GetAllEmployees" 
    UpdateMethod="UpdateEmployee" 
    DeleteMethod="DeleteEmployee"
    OnDeleting="ObjectDataSource1_Deleting">
    <UpdateParameters>
        <asp:Parameter Name="employeeID" Type="Int32" />
        <asp:Parameter Name="firstName" Type="String" />
        <asp:Parameter Name="lastName" Type="String" />
        <asp:Parameter Name="titleOfCourtesy" Type="String" />
    </UpdateParameters>
    <DeleteParameters>
        <asp:ControlParameter ControlID="GridView1" 
            Name="employeeID" Type="int32" />
    </DeleteParameters>
</asp:ObjectDataSource>

Теперь скорректируем управляющий столбец объекта GridView1, чтобы добавить в его пользовательский интерфейс кнопку для возможности удаления записи. Кнопку добавим в форме гиперссылки Link.

  • Вызовите встроенный визуальный редактор для объекта GridView1. Для этого щелкните на кнопке (пиктограмма треугольника) в правом верхнем углу визуального представления объекта, а затем на ссылке Edit Columns

  • Выделите управляющий столбец "Изменить" и в поле CommandField properties установите значения следующих свойств
    • ButtonType=Link
    • DeleteText="Удалить"
    • ShowDeleteButton="True"

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

ADO.NET отслеживает это положение автоматически, но ей нужно указать первичный ключ. Для этого служит параметр DataKeyNames в элементе управления GridView1 (поскольку мы планируем удалять запись через него), в котором указывается строка с одним именем ключевого поля или строка со списком ключевых полей, разделенных запятыми. В нашем случае первичным ключом в таблице Employees является поле EmployeeID.

  • Переведите редактор страницы в режим Source и добавьте в заголовок элемента GridView1 параметр, назначающий ключевое поле редактируемой таблицы
    • DataKeyNames="EmployeeID"
  • Выделите текстовую метку lblInfo и сбросьте свойство сохранения состояния EnableViewState="False", чтобы при каждом новом запросе ее значение очищалось

На этом этап декларативной настройки страницы закончен. Теперь нужно заполнить созданные нами ранее обработчики соответствующим кодом.

  • Заполните обработчики событий так, чтобы окончательный код страницы ObjectDataSourceFull.aspx стал следующим
    <%@ Page Language="C#" %>
        
    <script runat="server">
        
        protected void LinkButton1_Click(object sender, EventArgs e)
        {
            EmployeeDB db = new EmployeeDB();
            // Вставляем пустую запись и запоминаем ее номер
            Session["recordNumber"] = 
                db.InsertEmployee(new EmployeeDetails(0, "", "", ""));
            // Обновляем страницу без полного цикла,
            Server.Transfer(Request.FilePath);
        }
        
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Session["recordNumber"] != null)
            {
                lblInfo.Text = "Добавлена запись "
                    + Session["recordNumber"].ToString();
                Session.Remove("recordNumber");
            }
        }
        
        protected void ObjectDataSource1_Deleting(object sender, 
            ObjectDataSourceMethodEventArgs e)
        {
            lblInfo.Text = "Удалена запись " 
                + e.InputParameters["employeeID"].ToString();
        }
    </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:ObjectDataSource ID="ObjectDataSource1" runat="server"
                TypeName="EmployeeDB" SelectMethod="GetAllEmployees" 
                UpdateMethod="UpdateEmployee" 
                DeleteMethod="DeleteEmployee"
                OnDeleting="ObjectDataSource1_Deleting">
                <UpdateParameters>
                    <asp:Parameter Name="employeeID" Type="Int32" />
                    <asp:Parameter Name="firstName" Type="String" />
                    <asp:Parameter Name="lastName" Type="String" />
                    <asp:Parameter Name="titleOfCourtesy" Type="String" />
                </UpdateParameters>
                <DeleteParameters>
                    <asp:ControlParameter ControlID="GridView1" 
                        Name="employeeID" Type="int32" />
                </DeleteParameters>
            </asp:ObjectDataSource>
            <asp:GridView ID="GridView1" runat="server" 
                AutoGenerateColumns="False" DataSourceID="ObjectDataSource1" 
                DataKeyNames="EmployeeID">
                <Columns>
                    <asp:BoundField DataField="EmployeeID" HeaderText="№ п/п" />
                    <asp:BoundField DataField="FirstName" HeaderText="Имя" />
                    <asp:BoundField DataField="LastName" HeaderText="Фамилия" />
                    <asp:BoundField DataField="TitleOfCourtesy" HeaderText="Статус" />
                    <asp:CommandField 
                        CancelText="Отмена" EditText="Редакция" HeaderText="Изменить"
                        ShowEditButton="True" ShowHeader="True" UpdateText="Применить" 
                        DeleteText="Удалить" ShowDeleteButton="True">
                        <HeaderStyle BackColor="Red" ForeColor="Yellow" />
                    </asp:CommandField>
                </Columns>
            </asp:GridView>
            <asp:LinkButton ID="LinkButton1" runat="server" OnClick="LinkButton1_Click">
                Вставка
            </asp:LinkButton>
            <br />
            <asp:Label ID="lblInfo" runat="server" EnableViewState="False" />
        </div>
        </form>
    </body>
    </html>
  • Исполните страницу ObjectDataSourceFull.aspx и насладитесь тем, что она имеет функциональность полноценного редактора таблиц, тем более - удаленных (Ах да Большой Билл, ах да мала-ц-ц-а!). Один из экранов, генерируемых на стороне пользователя, будет таким
№ п/п Имя Фамилия Статус Изменить
1 Nancy Davolio Ms. Редакция/Удалить
2 Andrew Fuller Dr. Редакция/Удалить
3 Janet Leverling Ms. Редакция/Удалить
4 Margaret Peacock Mrs. Редакция/Удалить
5 Steven Buchanan Mr. Редакция/Удалить
6 Michael Suyama Mr. Редакция/Удалить
7 Robert King Mr. Редакция/Удалить
8 Laura Callahan Ms. Редакция/Удалить
9 Владимир Снетков Доцент 007 Редакция/Удалить
10 Редакция/Удалить

Вставка

Добавлена запись 10

Программное изменение запроса пользователя в SqlDataSource

Ранее мы рассматривали пример SqlDataSourceParameters.aspx выборки данных из таблицы в зависимости от выбранного пользователем города. Первый источник SqlDataSource заполнял городами список, жестко привязанный с помощью спискового свойства DataSourceID. Второй источник SqlDataSource отрабатывал один и тот же SQL-запрос с разными значениями параметра, полученными из списка в зависимости от выбора пользователя.

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

  • Сделайте копию страницы SqlDataSourceParameters.aspx с именем SqlDataSourceChange.aspx и назначьте ее стартовой
  • Выделите элемент DropDownList ID="lstCities" и очистите его свойство DataSourceID, тем самым мы отвяжем список от источника данных
  • Двойным щелчком на свободном месте Web-формы создайте обработчик загрузки страницы Page_Load()
  • Для второго источника SqlDataSource ID="sourceEmployees" через панель Properties создайте обработчик события Selecting
  • Заполните обработчики кодом так, чтобы окончательное описание страницы было следующим
<%@ Page Language="C#" %>
    
<script runat="server">
    
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!this.IsPostBack)// Первый запрос
        {
            // Инициировать запрос и привязать результаты
            lstCities.DataSource = sourceEmployeeCities.Select(
                DataSourceSelectArguments.Empty);
            lstCities.DataBind();
    
            // Добавить новый элемент в список
            lstCities.Items.Add("Все города");
            lstCities.SelectedIndex = lstCities.Items.Count - 1;
        }
    }
    
    void sourceEmployees_Selecting(object sender, 
                                   SqlDataSourceSelectingEventArgs e)
    {
        if ((string)e.Command.Parameters["@City"].Value == "Все города")
        {
            // Очистить коллекцию параметров
            e.Command.Parameters.Clear();
                
            // Изменить команду
            e.Command.CommandText = "SELECT EmployeeID, FirstName, LastName, "
                + "Title, City FROM Employees WHERE City!=''";
        }
    }
</script>
    
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h2>Выберите город</h2>
        <asp:SqlDataSource ID="sourceEmployeeCities" runat="server" 
            ConnectionString="<%$ connectionStrings:Northwind %>" 
            ProviderName="System.Data.SqlClient" 
            SelectCommand="SELECT DISTINCT City FROM Employees" />
        <asp:DropDownList ID="lstCities" runat="server" 
            AutoPostBack="True"
            DataTextField="City" />
            
        <h2>Проживающие сотрудники</h2>
        <asp:SqlDataSource ID="sourceEmployees" runat="server" 
            ConnectionString="<%$ connectionStrings:Northwind %>" 
            ProviderName="System.Data.SqlClient" 
            SelectCommand="SELECT EmployeeID, FirstName, LastName, 
                Title, City FROM Employees WHERE City=@City" 
                OnSelecting="sourceEmployees_Selecting">
            <SelectParameters>
                <asp:ControlParameter Name="City" ControlID="lstCities" 
                    PropertyName="SelectedValue" />
            </SelectParameters>
        </asp:SqlDataSource>
        <asp:GridView ID="GridView1" runat="server" 
            DataSourceID="sourceEmployees" />
    </div>
    </form>
</body>
</html>

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

Статический результат выполнения страницы SqlDataSourceChange.aspx следующий

Выберите город


Проживающие сотрудники

EmployeeID FirstName LastName Title City
9 Владимир Снетков Доцент ВАК Красноярск

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