Опубликован: 25.09.2008 | Доступ: свободный | Студентов: 3223 / 516 | Оценка: 4.32 / 3.98 | Длительность: 18:50:00
ISBN: 978-5-94774-991-5
Лекция 10:

Использование баз данных в приложениях ASP.NET

< Лекция 9 || Лекция 10: 12345678910

При создании методов, извлекающих данные из БД, необходимо учитывать, как и для чего будут применяться данные методы. Дело в том, что может существовать множество различных потребностей в извлекаемых из БД данных. Отличия в них сводятся к представлению извлеченных данных в различных форматах. Например, если необходимо организовывать вывод информации с применением таких элементов, как 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.

Результат работы программы трехуровневого взаимодействия с БД

Рис. 10.30. Результат работы программы трехуровневого взаимодействия с БД

Использование объекта ObjectDataSource

Создание пользовательского кода, реализующего возможность взаимодействия с базой данных, — достаточно трудоемкий процесс. К тому же такой способ позволяет связывать визуальные элементы с данными только в программном коде. Для получения возможности создания такой связи в режиме редактирования страницы можно использовать объект ObjectDataSource. Этот объект позволяет создавать связь между элементами управления, расположенными на Web-странице, и компонентами доступа к данным, реализованным в виде пользовательских классов. Но для этого необходимо, чтобы пользовательский класс доступа к данным подчинялся следующим правилам:

  1. Он не должен сохранять состояние.
  2. Он должен иметь конструктор по умолчанию, без аргументов.
  3. Вся логика должна быть сосредоточена в единственном классе.
  4. Он не должен содержать статических методов, предназначенных для извлечения и обновления записей.
  5. Он должен предоставлять результаты запроса при вызове единственного метода.
  6. Результатом запроса должна быть одна или несколько записей, которые могут быть представлены в виде коллекции, массива либо спискового объекта. Главное, чтобы он реализовывал интерфейс 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 для организации доступа к БД

Рис. 10.31. Окно результата использования объекта ObjectDataSource для организации доступа к БД

Как видно из этого примера, с точки зрения пользователя использование ObjectDataSource и принципов трехуровневой архитектуры построения приложений доступа к данным аналогично использованию объекта SqlDataSource. Однако это сходство скрывает целый ряд деталей, сильно отличающих принципы построения трехуровневых приложений от обычной архитектуры. Наиболее значимый эффект от использования этих принципов заключается в том, что при трехуровневой архитектуре организации доступа к данным Web-страница не содержит никакого кода SQL. Вместо этого вся работа выполняется классом ProductsDB. За счет этого приложение оказывается более гибким и легко модифицируемым при необходимости изменения механизмов доступа к данным. Более подробную информацию об использовании принципов построения трехуровневой архитектуры доступа к данным в приложении можно найти в справочной системе MSDN, а также в [ 1 ] .

< Лекция 9 || Лекция 10: 12345678910