Компоненты данных 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 с именами- InsertEmployeeDB.cs
- DeleteEmployeeDB.cs
- UpdateEmployeeDB.cs
- GetAllEmployeeDB.cs
- CountEmployeeDB.cs
- 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. Мы уверены, что они будут работать как надо, если правильно их использовать. Вот это и есть преимущество объектно-ориентированного программирования во всей его красе: обращайся правильно к интерфейсу класса - и все будет работать.

