Опубликован: 07.05.2010 | Доступ: свободный | Студентов: 1678 / 62 | Оценка: 4.56 / 4.06 | Длительность: 34:11:00
Лекция 12:

Компоненты данных ADO.NET

Добавление класса-оболочки для доступа к полям данных

Для облегчения доступа к данным таблицы Employees учебной базы данных Northwind создадим класс-оболочку с именем EmployeeDetails, который представит нужные нам поля в виде одноименных открытых свойств.

  • Через контекстное меню корня Web-дерева создайте каталог с предопределенным именем App_Code

  • Вызовите контекстное меню для созданного каталога App_Code и выполните команду Add New Item, чтобы добавить класс C# с именем EmployeeDetails в приложение
  • Заполните созданную оболочкой заготовку класса следующим кодом
    using System;
        
    public class EmployeeDetails
    {
        // Общий конструктор
        public EmployeeDetails(int employeeID, string firstName, 
            string lastName, string titleOfCourtesy)
        {
            this.employeeID = employeeID;
            this.firstName = firstName;
            this.lastName = lastName;
            this.titleOfCourtesy = titleOfCourtesy;
        }
        
        // Конструктор по умолчанию обязателен, 
        // если создали общий конструктор
        public EmployeeDetails()
        {
        }
        
        // Добавляем свойства класса
        private int employeeID;
        public int EmployeeID
        {
            get { return employeeID; }
            set { employeeID = value; }
        }
        private string firstName;
        public string FirstName
        {
            get { return firstName; }
            set { firstName = value; }
        }
        private string lastName;
        public string LastName
        {
            get { return lastName; }
            set { lastName = value; }
        }
        private string titleOfCourtesy;
        public string TitleOfCourtesy
        {
            get { return titleOfCourtesy; }
            set { titleOfCourtesy = value; }
        }
    }

Добавление класса-оболочки для операций с данными

Создадим класс, который в своих методах использует записанные нами ранее хранимые процедуры SQL-запросов к таблице Employees учебной базы данных Northwind. Воспользуемся новым средством частичных классов ( partial ) версии языка C#2.0 и разместим класс с операциями в нескольких файлах, в каждом из которых реализуем один специфический метод.

  • Вызовите контекстное меню для созданного каталога App_Code и выполните команду Add New Item, чтобы добавить в приложение класс C# с именем EmployeeDB в файле EmployeeDB.cs
  • Из объявлений пространств имен using, автоматически сгенерированных оболочкой, оставьте только using System; и добавьте в заголовок объявления класса ключевое слово partial (частичный), чтобы дать указание компилятору считать одноименные классы в отдельных файлах единым классом (нам так удобнее разместить код отдельных методов)
  • Сделайте в каталоге App_Code шесть копий файла EmployeeDB.cs с именами
    1. InsertEmployeeDB.cs
    2. DeleteEmployeeDB.cs
    3. UpdateEmployeeDB.cs
    4. GetAllEmployeeDB.cs
    5. CountEmployeeDB.cs
    6. GetEmployeeDB.cs
  • Заполните первую часть заготовки класса EmployeeDB в файле EmployeeDB.cs следующим кодом
    using System;
        
    using System.Web.Configuration;
        
    public partial class EmployeeDB
    {
        private string connectionString;
        public EmployeeDB()
        {
            // Извлечь из файла web.config строку соединения по умолчанию
            connectionString = WebConfigurationManager.
                ConnectionStrings["Northwind"].ConnectionString;
        }
        
        public EmployeeDB(string connectionStringCustom)
        {
            // Извлечь из файла web.config другую строку соединения
            connectionString = WebConfigurationManager.
                ConnectionStrings[connectionStringCustom].ConnectionString;
        }
    }

Обратите внимание, что мы по ходу дела добавляем к коду необходимые пространства имен инструкцией using.

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

using System;
using System.Data;
    
using System.Data.SqlClient;
    
public partial class EmployeeDB
{
    public int InsertEmployee(EmployeeDetails emp)
    {
        SqlConnection con = new SqlConnection(connectionString);
        SqlCommand cmd = new SqlCommand("InsertEmployee", con);
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add(new SqlParameter("@FirstName", SqlDbType.NVarChar, 10));
        cmd.Parameters["@FirstName"].Value = emp.FirstName;
        cmd.Parameters.Add(new SqlParameter("@LastName", SqlDbType.NVarChar, 20));
        cmd.Parameters["@LastName"].Value = emp.LastName;
        cmd.Parameters.Add(new SqlParameter("@TitleOfCourtesy", SqlDbType.NVarChar, 25));
        cmd.Parameters["@TitleOfCourtesy"].Value = emp.TitleOfCourtesy;
        cmd.Parameters.Add(new SqlParameter("@EmployeeID", SqlDbType.Int, 4));
        cmd.Parameters["@EmployeeID"].Direction = ParameterDirection.Output;
    
        try
        {
            con.Open();
            cmd.ExecuteNonQuery();
            return (int)cmd.Parameters["@EmployeeID"].Value;
        }
        catch
        {
            throw new ApplicationException("Ошибка данныx.");
        }
        finally
        {
            con.Close();
        }
    }
}
using System;
using System.Data;
    
using System.Data.SqlClient;
    
public partial class EmployeeDB
{
    public void DeleteEmployee(int employeeID)
    {
        SqlConnection con = new SqlConnection(connectionString);
        SqlCommand cmd = new SqlCommand("DeleteEmployee", con);
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add(new SqlParameter("@EmployeeID", SqlDbType.Int, 4));
        cmd.Parameters["@EmployeeID"].Value = employeeID;
    
        try
        {
            con.Open();
            cmd.ExecuteNonQuery();
        }
        catch
        {
            throw new ApplicationException("Ошибка данныx.");
        }
        finally
        {
            con.Close();
        }
    }
}
using System;
using System.Data;
    
using System.Data.SqlClient;
    
public partial class EmployeeDB
{
    public void UpdateEmployee(int employeeID, string firstName,
                               string lastName, string titleOfCourtesy)
    {
        SqlConnection con = new SqlConnection(connectionString);
        SqlCommand cmd = new SqlCommand("UpdateEmployee", con);
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add(new SqlParameter("@EmployeeID", SqlDbType.Int, 4));
        cmd.Parameters["@EmployeeID"].Value = employeeID;
        cmd.Parameters.Add(new SqlParameter("@FirstName", SqlDbType.NVarChar, 10));
        cmd.Parameters["@FirstName"].Value = firstName;
        cmd.Parameters.Add(new SqlParameter("@LastName", SqlDbType.NVarChar, 20));
        cmd.Parameters["@LastName"].Value = lastName;
        cmd.Parameters.Add(new SqlParameter("@TitleOfCourtesy", SqlDbType.NVarChar, 25));
        cmd.Parameters["@TitleOfCourtesy"].Value = titleOfCourtesy;
    
        try
        {
            con.Open();
            cmd.ExecuteNonQuery();
        }
        catch
        {
            throw new ApplicationException("Ошибка данныx.");
        }
        finally
        {
            con.Close();
        }
    }
}
using System;
using System.Data;
    
using System.Data.SqlClient;
using System.Collections.Generic;
    
public partial class EmployeeDB
{
    public List<EmployeeDetails> GetAllEmployees()
    {
        SqlConnection con = new SqlConnection(connectionString);
        SqlCommand cmd = new SqlCommand("GetAllEmployees", con);
        cmd.CommandType = CommandType.StoredProcedure;
    
        // Создать коллекцию для всех записей 
        List<EmployeeDetails> employees = new List<EmployeeDetails>();
    
        try
        {
            con.Open();
            SqlDataReader reader = cmd.ExecuteReader();
            while (reader.Read())
            {
                EmployeeDetails emp = new EmployeeDetails(
                (int)reader["EmployeeID"],
                (string)reader["FirstName"],
                (string)reader["LastName"],
                (string)reader["TitleOfCourtesy"]);
                employees.Add(emp);
            }
            reader.Close();
            return employees;
        }
        catch
        {
            throw new ApplicationException("Ошибка данныx.");
        }
        finally
        {
            con.Close();
        }
    }
}
using System;
using System.Data;
    
using System.Data.SqlClient;
    
public partial class EmployeeDB
{
    public int CountEmployees()
    {
        SqlConnection con = new SqlConnection(connectionString);
        SqlCommand cmd = new SqlCommand("CountEmployees", con);
        cmd.CommandType = CommandType.StoredProcedure;
    
        try
        {
            con.Open();
            return (int)cmd.ExecuteScalar();
        }
        catch
        {
            throw new ApplicationException("Ошибка данныx.");
        }
        finally
        {
            con.Close();
        }
    }
}
using System;
using System.Data;
        
using System.Data.SqlClient;
    
public partial class EmployeeDB
{
    public EmployeeDetails GetEmployee(int employeeID)
    {
        SqlConnection con = new SqlConnection(connectionString);
        SqlCommand cmd = new SqlCommand("GetEmployee", con);
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add(new SqlParameter("@EmployeeID", SqlDbType.Int, 4));
        cmd.Parameters["@EmployeeID"].Value = employeeID;
    
        try
        {
            con.Open();
            SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow);
            // Получить первую строку
            reader.Read();
            EmployeeDetails emp = new EmployeeDetails(
                (int)reader["EmployeeID"],
                (string)reader["FirstName"],
                (string)reader["LastName"],
                (string)reader["TitleOfCourtesy"]);
            reader.Close();
            return emp;
        }
        catch
        {
            throw new ApplicationException("Ошибка данныx.");
        }
        finally
        {
            con.Close();
        }
    }
}

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

Мы видим, что каждый метод сам открывает и закрывает соединение с базой данных. Все тонкости работы с данными скрыты внутри методов. Наша задача теперь, в нужном месте создать экземпляр класса EmployeeDB и правильно вызывать его методы, соблюдая установленный в них интерфейс. Раз создав этот класс, его можно применять многократно по мере необходимости, не заботясь об инкапсулированных в нем тонкостях программирования. Мы же не знаем (да и не хотим знать), как реализованы библиотечные классы .NET Framework. Мы уверены, что они будут работать как надо, если правильно их использовать. Вот это и есть преимущество объектно-ориентированного программирования во всей его красе: обращайся правильно к интерфейсу класса - и все будет работать.