Использование баз данных в приложениях ASP.NET
При создании методов, извлекающих данные из БД, необходимо учитывать, как и для чего будут применяться данные методы. Дело в том, что может существовать множество различных потребностей в извлекаемых из БД данных. Отличия в них сводятся к представлению извлеченных данных в различных форматах. Например, если необходимо организовывать вывод информации с применением таких элементов, как GridView, удобнее всего сделать так, чтобы метод вернул такую структуру, которую можно использовать для привязки данных к этому элементу. К таким структурам, как уже было сказано выше, относятся DataReader, DataTable, DataSet и т. д. Если нужно извлекать данные об одном товаре, необходимо, чтобы метод возвращал объект Product, если же желательно, чтобы метод извлекал список существующих товаров, представленных в БД и необходимых для их обработки, удобнее, чтобы метод вернул массив объектов Product. В реальных приложениях может потребоваться несколько методов, предназначенных для реализации различных режимов работы с БД. Например, для отображения вызывается один метод, извлекающий данные из БД, а для их редактирования - другой.
Создадим метод GetProductsTable(), предназначенный для извлечения данных о товарах из таблицы "Товары" и помещения их в объект DataTable. Исходный код этого метода приведен ниже.
public DataTable GetProductsTable()
{
SqlConnection con = new SqlConnection(connectionString);
string query = "SELECT КодТовара,НаименованиеТовара,Цена
FROM Товары";
SqlCommand cmd = new SqlCommand(query, con);
cmd.CommandType = CommandType.Text;
SqlDataAdapter da = new SqlDataAdapter(query, con);
DataTable dt = new DataTable("Product");
try
{
con.Open();
da.Fill(dt);
return dt;
}
catch (SqlException e)
{
throw new ApplicationException("Ошибка чтения списка
товаров из таблицы Товары");
}
finally
{
con.Close();
}
}В дальнейшем полученный в результате такой операции результат может быть использован для отображения данных в объекте GridView.
В качестве примера создадим также метод для извлечения данных из таблицы "Товары" и предоставления вызывающей программе объекта DataReader, с помощью которого осуществляется чтение данных из БД. Исходный код метода GetProductsReader(), реализующего данную операцию, представлен ниже.
public SqlDataReader GetProductsReader()
{
SqlConnection con = new SqlConnection(connectionString);
string query = "SELECT КодТовара,НаименованиеТовара,Цена
FROM Товары";
SqlCommand cmd = new SqlCommand(query, con);
cmd.CommandType = CommandType.Text;
try
{
con.Open();
return cmd.ExecuteReader();
}
catch (SqlException e)
{
throw new ApplicationException("Ошибка чтения списка
товаров из таблицы Товары");
}
}Особенностью метода является то, что в нем открывается соединение с базой данных, но не закрывается. Это объясняется тем, что основная программа, которой передается объект DataReader, должна осуществлять чтение данных из него, а для этого необходимо открытое соединение.
Описанные выше методы позволяют получать данные о товарах из БД в формате, лучше всего приспособленном для их отображения на экране, но плохо подходящем для редактирования данных. Для получения данных о товарах в удобном для программной работы с ними формате создадим еще два метода. Первый предназначен для извлечения из БД информации об одном товаре и передаче ее в вызывающую программу в виде объекта Product. Второй - для формирования массива объектов Product. Оба метода используют объект DataReader для чтения информации из БД.
public Product GetProduct(int productID)
{
SqlConnection con = new SqlConnection(connectionString);
string query = "SELECT КодТовара,НаименованиеТовара,Цена
FROM Товары WHERE КодТовара=@ID";
SqlCommand cmd = new SqlCommand(query, con);
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add("@ID", SqlDbType.Int, 4);
cmd.Parameters["@ID"].Value = productID;
try
{
con.Open();
SqlDataReader rdr = cmd.ExecuteReader
(CommandBehavior.SingleRow);
rdr.Read();
int pID=(int)rdr["КодТовара"];
string pName = rdr["НаименованиеТовара"].ToString();
double pCost = Convert. ToDouble(rdr["Цена"]);
Product prod = new Product(pID,pName,pCost);
rdr.Close();
return prod;
}
catch (SqlException e)
{
throw new ApplicationException("Ошибка извлечения товара
из таблицы Товары");
}
finally
{
con.Close();
}
}
public List<Product> GetProducts()
{
SqlConnection con = new SqlConnection(connectionString);
string query = "SELECT КодТовара,НаименованиеТовара,Цена
FROM Товары";
SqlCommand cmd = new SqlCommand(query, con);
cmd.CommandType = CommandType.Text;
List<Product> products = new List<Product>();
try
{
con.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Product prod =
new Product((int) rdr["КодТовара"], rdr["Наименование
Товара"].ToString(), (double) rdr["Цена"]);
products.Add(prod);
}
rdr.Close();
return products;
}
catch (SqlException e)
{
throw new ApplicationException("Ошибка извлечения списка
товаров из таблицы Товары");
}
finally
{
con.Close();
}
}Для демонстрации использования созданного слоя доступа к данным поместим на форму объект ProductsView класса GridView, а также создадим следующий код, использующий возможности класса ProductsDB.
protected void Page_Load(object sender, EventArgs e)
{
//Создание нового объекта доступа к данным
ProductsDB prodDB = new ProductsDB("TEST_DB");
if (!Page.IsPostBack)
{
//Создание нового объекта Product
Product prod = new Product(31, "Товар31", 99);
//Добавление созданного объекта Product в таблицу БД
prodDB.AddProduct(prod);
//Получение из БД информации о товаре с кодом 5
Product product = prodDB.GetProduct(5);
//Изменение наименования полученного товара
product.ProductName = "Товар1000";
//Изменение цены полученного товара
product.ProductCost = 10.5;
//Обновление информации о товаре в БД
prodDB.UpdateProduct(product);
//Получение массива объектов Product. Количество объектов
//равно количеству записей в таблице Товары
List<Product> products = prodDB.GetProducts();
}
//Установить источник данных и осуществить их привязку
//для элемента GridView
ProductsView.DataSource = prodDB.GetProductsTable();
Page.DataBind();
}Для демонстрации возможности удаления данных из таблицы "Товары" поместим на форму кнопку и создадим следующий обработчик события нажатия на нее:
protected void Button1_Click(object sender, EventArgs e)
{
ProductsDB prodDB = new ProductsDB("TEST_DB");
prodDB.DeleteProduct(31);
ProductsView.DataSource = prodDB.GetProductsReader();
Page.DataBind();
}В этом методе вновь осуществляется установка источника данных для объекта GridView, а также их привязка. Это необходимо для того, чтобы отобразить изменения в данных, произведенных ранее выполненными действиями.
Результат работы программы представлен на рис. 10.30.
Использование объекта ObjectDataSource
Создание пользовательского кода, реализующего возможность взаимодействия с базой данных, — достаточно трудоемкий процесс. К тому же такой способ позволяет связывать визуальные элементы с данными только в программном коде. Для получения возможности создания такой связи в режиме редактирования страницы можно использовать объект ObjectDataSource. Этот объект позволяет создавать связь между элементами управления, расположенными на Web-странице, и компонентами доступа к данным, реализованным в виде пользовательских классов. Но для этого необходимо, чтобы пользовательский класс доступа к данным подчинялся следующим правилам:
- Он не должен сохранять состояние.
- Он должен иметь конструктор по умолчанию, без аргументов.
- Вся логика должна быть сосредоточена в единственном классе.
- Он не должен содержать статических методов, предназначенных для извлечения и обновления записей.
- Он должен предоставлять результаты запроса при вызове единственного метода.
- Результатом запроса должна быть одна или несколько записей, которые могут быть представлены в виде коллекции, массива либо спискового объекта. Главное, чтобы он реализовывал интерфейс IEnumerable.
Использование ObjetDataSource в ряде случаев бывает гораздо удобнее применения таких элементов доступа к данным, как SqlDataSource или AccessDataSource. Скажем, в предыдущем примере для доступа к таблице "Товары" можно воспользоваться пользовательским классом и объектом ObjectDataSource. Для этого необходимо выполнить нижеследующие шаги.
Поместить на форму объект ObjectDataSource, перетащив его с панели Toolbox, после чего прикрепить к нему класс, отвечающий за извлечение данных, - в нашем случае это ProductsDB. Для этого достаточно установить значение свойства TypeName равным ProductsDB. После этого необходимо определить свойства SelectMethod, DeleteMethod, UpdateMethod и InsertMethod, используемые для выполнения соответствующих операций над данными в БД. В качестве значений этих свойств нужно установить имя метода, выполняющего соответствующие операции. Так, в качестве значения свойства SelectMethod в данном примере установим имя метода, извлекающего данные из БД, - GetProducts. Этот метод удовлетворяет всем критериям ObjectDataSource - он возвращает объект, представляющий все данные через общедоступные свойства. Имена этих свойств и будут использованы в качестве имен столбцов при выводе информации на экран в табличной форме. После того как связь ObjectDataSource с классом, извлекающим данные из базы данных, установлена, необходимо добавить на Web-форму элемент GridView и связать их, установив в свойстве DataSourceID этого элемента имя объекта ObjectDataSource. Определение ObjectDataSource и GridView тогда будет выглядеть следующим образом:
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
SelectMethod="GetProducts"
TypeName="ProductsDB"></asp:ObjectDataSource>
<br />
<asp:GridView ID="GridView1" runat="server"
AutoGenerateColumns="False" DataSourceID="ObjectDataSource1">
<Columns>
<asp:BoundField DataField="ProductID"
HeaderText="ProductID" SortExpression="ProductID" />
<asp:BoundField DataField="ProductName"
HeaderText="ProductName" SortExpression="ProductName" />
<asp:BoundField DataField="ProductCost"
HeaderText="ProductCost" SortExpression="ProductCost" />
</Columns>
</asp:GridView>Результат работы программы показан на рис. 10.31.
Как видно из этого примера, с точки зрения пользователя использование ObjectDataSource и принципов трехуровневой архитектуры построения приложений доступа к данным аналогично использованию объекта SqlDataSource. Однако это сходство скрывает целый ряд деталей, сильно отличающих принципы построения трехуровневых приложений от обычной архитектуры. Наиболее значимый эффект от использования этих принципов заключается в том, что при трехуровневой архитектуре организации доступа к данным Web-страница не содержит никакого кода SQL. Вместо этого вся работа выполняется классом ProductsDB. За счет этого приложение оказывается более гибким и легко модифицируемым при необходимости изменения механизмов доступа к данным. Более подробную информацию об использовании принципов построения трехуровневой архитектуры доступа к данным в приложении можно найти в справочной системе MSDN, а также в [ 1 ] .

