Как правило, в практических приложениях создание соединения и доступ к данным оформляется в виде отдельного класса, который называют компонентом данных. В него также включают класс , который загружает данные и играет роль не является обязательным для страниц ASP.NET, однако он предоставляет большую гибкость в работе с данными, включая
Компонент данных как класс должен содержать все необходимые методы и свойства для работы с данными. Чтобы выполнить операцию базы данных, на странице создается экземпляр этого класса-компонента данных и вызываются соответствующие методы. Рассмотрим способы создания этого вспомогательного пользовательского класса.
При создании хорошо спроектированного класса-компонента данных нужно следовать некоторым рекомендациям:
WHERE или TOP , ограничивающие диапазон На следующем рисунке показан рекомендуемый многослойный дизайн работы с базой данных.

Реализуем этот простой дизайн в непростом примере. Разработаем страницу, в которой будем работать с таблицей Employees учебной базы данных Northwind.
Создайте новый сайт командой File/New/Web Site с именем Мы хотим создать структурированный код в виде компонента данных, который будет состоять из класса-оболочки доступа к полям таблицы и класса обработки записей таблицы.
Прежде чем начать кодировать логику доступа к таблице Employees, создадим и запишем в базу данных набор
Добавьте к приложению командой Website/Add Existing Item страницу TestStoredProcedure.aspx из каталога WebSite7 и переименуйте ее в SaveStoredProcedure.aspx
Аналогичным образом добавьте к приложению файл Web.Config из каталога WebSite7 с готовой строкой соединения и откорректируйте его так(рис ) Файл Web.Config<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="Northwind" connectionString="Data Source=localhost;
Initial Catalog=Northwind; user id=sa; password=;" />
</connectionStrings>
<system.web>
<compilation debug="true"/>
</system.web>
</configuration>
Откорректируйте страницу SaveStoredProcedure.aspx следующим образом(рис ) Код страницы SaveStoredProcedure.aspx одноразовой записи хранимых процедур<%@ Page Language="C#" %>
<script runat="server">
// Объявления хранимых процедур
// Вставка записи
string sql1 =
"CREATE PROCEDURE InsertEmployee "
+ "@EmployeeID int OUTPUT,"
+ "@FirstName varchar(10),"
+ "@LastName varchar(20),"
+ "@TitleOfCourtesy varchar(25) "
+ "AS "
+ "INSERT INTO Employees "
+ "(TitleOfCourtesy, LastName, FirstName, HireDate) "
+ "VALUES(@TitleOfCourtesy, @LastName, @FirstName, GETDATE()) "
+ "SET @EmployeeID = @@IDENTITY";
// Удаление записи
string sql2 =
"CREATE PROCEDURE DeleteEmployee "
+ "@EmployeeID int "
+ "AS "
+ "DELETE FROM Employees WHERE EmployeeID = @EmployeeID";
// Обновление записи
string sql3 =
"CREATE PROCEDURE UpdateEmployee "
+ "@EmployeeID int, "
+ "@FirstName varchar(10),"
+ "@LastName varchar(20),"
+ "@TitleOfCourtesy varchar(25) "
+ "AS "
+ "UPDATE Employees "
+ "SET "
+ "FirstName = @FirstName,"
+ "LastName = @LastName,"
+ "TitleOfCourtesy = @TitleOfCourtesy "
+ "WHERE EmployeeID = @EmployeeID";
// Выбрать все
string sql4 =
"CREATE PROCEDURE GetAllEmployees "
+ "AS "
+ "SELECT EmployeeID, FirstName, LastName, TitleOfCourtesy "
+ "FROM Employees";
// Подсчитать число записей
string sql5 =
"CREATE PROCEDURE CountEmployees "
+ "AS "
+ "SELECT COUNT(EmployeeID) "
+ "FROM Employees";
// Выбрать запись
string sql6 =
"CREATE PROCEDURE GetEmployee "
+ "@EmployeeID int "
+ "AS "
+ "SELECT EmployeeID, FirstName, LastName, TitleOfCourtesy "
+ "FROM Employees "
+ "WHERE EmployeeID = @EmployeeID";
protected void Page_Load(object sender, EventArgs e)
{
// Извлекли строку соединения из web.config
string connectString = System.Web.Configuration.WebConfigurationManager.
ConnectionStrings["Northwind"].ConnectionString;
// Создали объект соединения
System.Data.SqlClient.SqlConnection con =
new System.Data.SqlClient.SqlConnection(connectString);
// Создали объект Command
System.Data.SqlClient.SqlCommand cmd =
new System.Data.SqlClient.SqlCommand();
// Настроили объект Command
cmd.Connection = con;
cmd.CommandType = System.Data.CommandType.Text;
lblInfo.Text = "";
// Открываем соединение в безопасном режиме
try
{
con.Open();
}
catch
{
con.Close();
return;
}
// Выполняем команды в безопасном режиме
// Удаляем процедуры на случай повторного запуска этой страницы
try
{
cmd.CommandText = "DROP PROCEDURE InsertEmployee";
cmd.ExecuteNonQuery();
lblInfo.Text += "Прошли \"DROP PROCEDURE InsertEmployee\"<br />";
}
catch { }
try
{
cmd.CommandText = "DROP PROCEDURE DeleteEmployee";
cmd.ExecuteNonQuery();
lblInfo.Text += "Прошли \"DROP PROC DeleteEmployee\"<br />";
}
catch { }
try
{
cmd.CommandText = "DROP PROCEDURE UpdateEmployee";
cmd.ExecuteNonQuery();
lblInfo.Text += "Прошли \"DROP PROCEDURE UpdateEmployee\"<br />";
}
catch { }
try
{
cmd.CommandText = "DROP PROCEDURE GetAllEmployees";
cmd.ExecuteNonQuery();
lblInfo.Text += "Прошли \"DROP PROCEDURE GetAllEmployees\"<br />";
}
catch { }
try
{
cmd.CommandText = "DROP PROCEDURE CountEmployees";
cmd.ExecuteNonQuery();
lblInfo.Text += "Прошли \"DROP PROCEDURE CountEmployees\"<br />";
}
catch { }
try
{
cmd.CommandText = "DROP PROCEDURE GetEmployee";
cmd.ExecuteNonQuery();
lblInfo.Text += "Прошли \"DROP PROCEDURE GetEmployee\"<br />";
}
catch { }
// Выполняем команды в безопасном режиме
// Добавляем в базу данных хранимые процедуры
try
{
cmd.CommandText = sql1;
cmd.ExecuteNonQuery();
lblInfo.Text += "Прошли \"CREATE PROCEDURE InsertEmployee\"<br />";
}
catch { }
try
{
cmd.CommandText = sql2;
cmd.ExecuteNonQuery();
lblInfo.Text += "Прошли \"CREATE PROCEDURE DeleteEmployee\"<br />";
}
catch { }
try
{
cmd.CommandText = sql3;
cmd.ExecuteNonQuery();
lblInfo.Text += "Прошли \"CREATE PROCEDURE UpdateEmployee\"<br />";
}
catch { }
try
{
cmd.CommandText = sql4;
cmd.ExecuteNonQuery();
lblInfo.Text += "Прошли \"CREATE PROCEDURE GetAllEmployees\"<br />";
}
catch { }
try
{
cmd.CommandText = sql5;
cmd.ExecuteNonQuery();
lblInfo.Text += "Прошли \"CREATE PROCEDURE CountEmployees\"<br />";
}
catch { }
try
{
cmd.CommandText = sql6;
cmd.ExecuteNonQuery();
lblInfo.Text += "Прошли \"CREATE PROCEDURE GetEmployee\"<br />";
}
catch { }
finally
{
con.Close();
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<asp:Label ID="lblInfo" runat="server" />
</form>
</body>
</html>
Выполните страницу SaveStoredProcedure.aspx, чтобы добавить в базу Для облегчения доступа к данным таблицы Employees учебной базы данных Northwind создадим класс-оболочку с именем EmployeeDetails, который представит нужные нам поля в виде одноименных открытых свойств.
Через контекстное меню корня Web-дерева создайте каталог с предопределенным именем
Вызовите контекстное меню для
Заполните созданную оболочкой заготовку класса следующим кодом(рис ) Код класса EmployeeDetails.csusing 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; }
}
}
Создадим класс, который в своих методах использует записанные нами ранее Employees учебной базы данных Northwind. Воспользуемся новым средством частичных классов ( partial ) версии языка C#2.0 и разместим класс с операциями в нескольких файлах, в каждом из которых реализуем один специфический метод.
Вызовите контекстное меню для EmployeeDB в файле EmployeeDB.cs
Из объявлений пространств имен using, автоматически сгенерированных оболочкой, оставьте только using System; и добавьте в заголовок объявления класса ключевое слово partial (частичный), чтобы дать указание компилятору считать одноименные классы в отдельных файлах единым классом (нам так удобнее разместить код отдельных методов)
Сделайте в каталоге App_Code шесть копий файла EmployeeDB.cs с именамиInsertEmployeeDB.csDeleteEmployeeDB.csUpdateEmployeeDB.csGetAllEmployeeDB.csCountEmployeeDB.csGetEmployeeDB.cs
Заполните первую часть заготовки класса EmployeeDB в файле EmployeeDB.cs следующим кодом(рис ) Часть класса EmployeeDB в файле EmployeeDB.csusing 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 и правильно вызывать его методы, соблюдая установленный в них интерфейс. Раз создав этот класс, его можно применять многократно по мере необходимости, не заботясь об инкапсулированных в нем тонкостях программирования. Мы же не знаем (да и не хотим знать), как реализованы библиотечные классы .. Мы уверены, что они будут работать как надо, если правильно их использовать. Вот это и есть преимущество
Весь код класса-оболочки, который мы разработали выше, теперь нужно испытать на тестовой странице.
Добавьте к проекту (в корень Web-дерева) новую страницу с разделяемым кодом и именем TestComponent.aspx
Добавьте на страницу компонент Label и дайте ему имя lblInfo
Откройте на редактирование файл поддержки TestComponent.aspx.cs и наполните его следующим кодом(рис ) Файл поддержки TestComponent.aspx.cs тестовой страницы TestComponent.aspxusing System;
using System.Text;
using System.Collections.Generic;
public partial class TestComponent : System.Web.UI.Page
{
// Создать компонент базы данных
private EmployeeDB db = new EmployeeDB();
protected void Page_Load(object sender, EventArgs e)
{
lblInfo.Text = "<h2>Исходная таблица</h2>";
WriteEmployeesList();
int empID = db.InsertEmployee(
new EmployeeDetails(0, "Алексей", "Зиборов", "Ст."));
lblInfo.Text += "<h2>Вставлена 1 запись.</h2>";
WriteEmployeesList();
db.DeleteEmployee(empID);
lblInfo.Text += "<h2>Удалена 1 запись.</h2>";
WriteEmployeesList();
}
private void WriteEmployeesList()
{
StringBuilder htmlStr = new StringBuilder("");
List<EmployeeDetails> employees = db.GetAllEmployees();
foreach (EmployeeDetails emp in employees)
{
htmlStr.Append("<li>");
htmlStr.Append(emp.EmployeeID);
htmlStr.Append(" ");
htmlStr.Append(emp.TitleOfCourtesy);
htmlStr.Append(" <b>");
htmlStr.Append(emp.FirstName);
htmlStr.Append("</b>, ");
htmlStr.Append(emp.LastName);
htmlStr.Append("</li>");
}
int numEmployees = db.CountEmployees();
htmlStr.Append("<hr />Число записей: <b>");
htmlStr.Append(numEmployees.ToString());
htmlStr.Append("</b><br /><br />");
lblInfo.Text += htmlStr.ToString();
}
}
Назначьте страницу TestComponent.aspx стартовой и исполните ее. Должен получиться примерно такой результатИсходная таблица
Число записей: 9
Вставлена 1 запись.
Число записей: 10
Удалена 1 запись.
Число записей: 9
Мы видим, что все работает как надо. Обратите внимание, что значение поля EmployeeID прирастает на 1 при повторных запусках тестовой страницы. Это значит, что DELETE, а поле имеет установку для СУБД SQL Server, которая является посредником в нашем коде доступа к данным, автоматически увеличивать значение счетчика.
До сих пор мы рассматривали код, который работает непосредственно с физическими данными, хранящимися в базе данных, удерживая соединение на весь период обработки. Такой режим называется
Для таких целей применяется объект , который наполняется копией информации, прочитанной из базы, и далее служит виртуальным
имеет методы, которые могут читать и писать данные и схемы XML, методы для быстрой очистки и
| Метод | Описание |
|---|---|
|
Очищает все данные таблиц, но не трогает информацию о схеме и отношениях |
Copy() |
Возвращает точный дубликат с тем же набором таблиц, данных и отношений |
|
Возвращает с той же структурой (таблицами и отношениями), но без данных |
|
Принимает на входе другой и объединяет его с текущим , добавляя новые таблицы и объединяя данные в существующих |
GetXml(), GetXmlSchema() |
Возвращают . Информация схемы - это структурированная информация наподобие количества таблиц, их имен, столбцов, типов данных и установленных отношений |
ReadXml(), ReadXmlSchema() |
Создают таблицы в на основе существующего документа XML или документа схемы XML. Источником XML может быть файл или другой поток |
WriteXml(), WriteXmlSchema() |
в файле или потоке формата XML |
Класс является сердцем автономного доступа к данным. Он содержит в себе в виде классов-свойств коллекцию из нуля или более таблиц и коллекцию из нуля или более отношений между таблицами. Базовая структура приведена на рисунке.

Каждая запись представлена как объект DataRow. DataRow - это контейнер для действительных значений полей. К полям записи можно обращаться через объект DataRow как к myRow[".
Все версии измененных строк при редактировании сохраняются в для возможности , а все изменения производятся в виртуальном источнике оперативной памяти.
никогда не оставляет открытым System.Data.. Класс DbDataAdapter служит посредником между одним DataTable в и DbDataAdapter наследует от System.Data. и предоставляет три ключевых метода, приведенные в таблице
| Метод | Описание |
|---|---|
|
Заполняет данными за счет выполнения запроса в свойстве SelectCommand. Если запрос возвращает множественные результирующие наборы, то этот метод добавит множество объектов DataTable за одно обращение. Его можно также использовать для заполнения данными одного существующего объекта DataTable |
FillSchema() |
Заполняет информацией о структуре таблицы или множества таблиц |
Update() |
Обновляет данные из в |
Чтобы позволить DbDataAdapter изменять данные в источнике, нужно специфицировать объекты System.Data. для свойств UpdateCommand, InsertCommand, DeleteCommand объекта DbDataAdapter. Чтобы использовать DbDataAdapter для наполнения , потребуется установить свойство SelectCommand.
Класс System.Data. является базовым для более специализированных классов
System.Data.SqlClient.SqlDataAdapterSystem.Data.Odbc .OdbcDataAdapterSystem.Data.OleDb.OleDbDataAdapterSystem.Data.OracleClient.OracleDataAdapterкоторые в конечном итоге мы и должны использовать в своих приложениях.
Продемонстрируем на простом примере через DataAdapter. Данные будем извлекать из таблицы Employees учебной базы данных Northwind, поддерживаемой SQL Server. При этом автоматически создаст соединение, добавит в свою коллекцию DataTables объект DataTable, в котором каждую запись разместит в отдельном объекте DataRow коллекции DataRows. После этого
Добавьте к корневому узлу приложения страницу TestDataSet.aspx с разделяемым кодом и сделайте ее стартовой
Поместите на страницу элемент управления Label с именем lblInfo
Откройте файл поддержки TestDataSet.aspx.cs и наполните его следующим кодомusing System;
using System.Data;
using System.Web.Configuration;
using System.Data.SqlClient;
using System.Text;
public partial class TestDataSet : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Извлекаем строку соединения с именем Northwind из файла web.config
string connectionString = WebConfigurationManager.
ConnectionStrings["Northwind"].ConnectionString;
// Формируем строку SQL для выборки всех данных таблицы Employees
string commandString = "SELECT * FROM Employees";
// Создаем и настраиваем экземпляр класса SqlDataAdapter
SqlDataAdapter adapter =
new SqlDataAdapter(commandString, connectionString);
// Создаем объект DataSet результирующего набора данных
DataSet dataset = new DataSet();
// Безопасно заполняем данными объект DataTable с произвольным
// именем, например "EmployeesResult", созданного объекта DataSet
try
{
adapter.Fill(dataset, "EmployeesResult");
}
catch
{
throw new ApplicationException("Ошибка данныx.");
}
// Перебираем все объекты DataRow с полученным записами
StringBuilder htmlStr = new StringBuilder("");
foreach (DataRow dr in dataset.Tables["EmployeesResult"].Rows)
{
htmlStr.Append("<li>");
htmlStr.Append(dr["TitleOfCourtesy"].ToString());
htmlStr.Append(" <b>");
htmlStr.Append(dr["FirstName"].ToString());
htmlStr.Append("</b>, ");
htmlStr.Append(dr["LastName"].ToString());
htmlStr.Append("</li>");
}
// Отображаем полученные данные
lblInfo.Text = "<h2>Список сотрудников</h2>";
lblInfo.Text += htmlStr.ToString();
}
}
Строка
adapter.Fill(dataset, "EmployeesResult");
выполняет DataTable коллекции DataTables объекта класса . Мы указали явно имя создаваемого объекта DataTable, которое выбрали произвольно. Если этого не сделать, автоматически будет назначено имя по умолчанию.
При заполнении метода соединение открывается и закрывается автоматически. Именно его мы заключили в операторы DataAdapter только использует его и не будет закрывать по окончании работы. Это удобно, когда нужно выполнить несколько последовательных операций с DataAdapter. Только нужно не забыть закрыть соединение, когда оно не станет нужным.
На последнем этапе нашего кода мы опрашиваем коллекцию строк результирующего набора данных и выводим их в текстовую метку lblInfo. Такой подход к отображению данных редко применяется. Более удобной является техника
Исполните страницу TestDataSet.aspx и получите такой результатСписок сотрудников
Следует помнить, что объекты полученных данных существуют только на время жизни страницы. При следующем запросе всю работу по , либо в объекте .
Рассмотрим пример, в котором демонстрируется более интересное применение , которое в дополнение к представлению автономных данных использует отношения таблиц. Этот пример показывает, как извлекать некоторые записи из таблиц и базы данных Northwind. В нем также показано, как создавать отношения между таблицами для организации простой
Добавьте к корневому узлу приложения страницу DataSetRelationShips.aspx с разделяемым кодом и сделайте ее стартовой
Поместите на страницу элемент управления Label с именем lblInfo
Откройте файл поддержки DataSetRelationShips.aspx.cs и наполните его следующим кодомusing System;
using System.Data;
using System.Web.Configuration;
using System.Data.SqlClient;
using System.Text;
public partial class DataSetRelationShips : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Извлекаем строку соединения с именем Northwind из файла web.config
string connectionString = WebConfigurationManager.
ConnectionStrings["Northwind"].ConnectionString;
// Создаем объект соединения
SqlConnection con = new SqlConnection(connectionString);
// Формируем строки SQL-запросов
string sqlCategories = "SELECT CategoryID, CategoryName FROM Categories";
string sqlProducts = "SELECT ProductName, CategoryID FROM Products";
// Создаем объект DataAdapter
SqlDataAdapter adapter = new SqlDataAdapter(sqlCategories, con);
// Создаем пустой объект DataSet набора данных
DataSet dataset = new DataSet();
// Выполняем два запроса к БД с открытием
// и закрытием соединения вручную.
// Возможные исключения не обрабатываем, а просто подавляем
try
{
con.Open();
// Наполнить DataSet данными из таблицы Categories
// с именованной меткой CatTable
adapter.Fill(dataset, "CatTable");
// Сменить команду и добавить в DataSet данные
// с именованной меткой ProdTable из таблицы Products
adapter.SelectCommand.CommandText = sqlProducts;
adapter.Fill(dataset, "ProdTable");
}
finally
{
con.Close();
}
// Определение отношения между извлеченными в DataSet
// именованными данными CatTable и ProdTable
DataRelation relation = new DataRelation(
"CatProd", // Имя отношения
dataset.Tables["CatTable"].Columns["CategoryID"], // Родительская таблица
dataset.Tables["ProdTable"].Columns["CategoryID"] // Дочерняя таблица
);
// Добавление отношения в коллекцию отношений DataSet
dataset.Relations.Add(relation);
// Перебираем все извлеченные категории продуктов
// и для каждой из них собираем сопоставленные продукты
StringBuilder htmlStr = new StringBuilder("");
foreach (DataRow row in dataset.Tables["CatTable"].Rows)
{
htmlStr.Append("<b>");
htmlStr.Append(row["CategoryName"].ToString()); // Имя поля
htmlStr.Append("</b>");
// Собираем дочерние записи из ProdTable для
// текущего значения родителя CatTable в массив
DataRow[] childRows = row.GetChildRows(relation);
htmlStr.Append("<ul>"); // Открыли маркированный список HTML
foreach (DataRow childRow in childRows)
{
htmlStr.Append("<li>"); // Элемент маркированного списка HTML
htmlStr.Append(childRow["ProductName"].ToString()); // Имя поля
htmlStr.Append("</li>");
}
htmlStr.Append("</ul>"); // Закрыли маркированный список HTML
}
// Отображаем полученные данные ненавистному пользователю
lblInfo.Text = htmlStr.ToString();
}
}
Прежде всего мы извлекаем из DataAdapter для будущего подключения и DataTable коллекции DataTables предварительно созданного объекта .
Мы используем один объект DataAdapter, предварительно настраивая его на выполнение разных SQL-команд. Но можно создать два отдельных объекта DataAdapter для каждой таблицы. Создавать отдельные объекты DataAdapter нужно обязательно в том случае, если мы планируем не только читать данные из таблицы, но и сохранять (подтверждать) изменения в
Таблицы и связаны в базе данных по ключевому полю CategoryID отношением "один в ко многим в ". Это поле является и внешним ключем таблицы . Это отношение не передается в объект из базы данных автоматически и мы вынуждены сами повторять его в коде для
Именованное отношение создается путем определения объекта DataRelation и добавления его в коллекцию отношений объекта . При создании объекта DataRelation в его конструкторе мы указываем три параметра: имя отношения, имя поля первичного ключа
Замечание. Когда мы добавляем отношение таблиц в , то должны соблюдать условие ссылочной целостности. Например, мы не можем удалить родительскую запись, если существуют связанные с ней дочерние строки, и не можем создать дочернюю запись, ссылающуюся на несуществующую родительскую. Это может стать причиной проблем, если в скопированы частичные данные из двух разных таблиц. На уровне физического источника полных данных с частичными данными может быть нарушена.
Например, если мы из одной таблицы извлекли полный список всех заказов, а из другой таблицы извлекли частичный список заказчиков, то часть списка заказов будет ссылаться в виртуальном источнике на несуществующих в нем заказчиков.
Один из способов обойти эту проблему - создать DataRelation с перегруженным конструктором, имеющим четвертый булевский параметр createConstraints, которому нужно задать значение false. Другой подход состоит в отключении способности проверять в значение false.
Долее мы работаем с автономными данными в отсоединенном режиме. Для мы организуем два цикла полного перебора элементов.
Во внешнем цикле мы перебираем все считанные из источника записи родительской таблицы. Для каждой из этих записей родителя мы создаем
Во внутреннем цикле мы перебираем все элементы
Исполните страницу DataSetRelationShips.aspx и получите следующий результатBeverages
Condiments
Confections
Dairy Products
Grains/Cereals
Meat/Poultry
Produce
Seafood
Класс DataTable имеет метод Select(), позволяющий извлекать из заполненного массив объектов-строк DataRow по дополнительному условию на основе SQL-выражения. Чтобы проиллюстрировать этот метод, модифицируем последний пример.
Сделайте из страницы DataSetRelationShips.aspx копию с именем DataTableSelect.aspx
Заполните файл DataTableSelect.aspx.cs следующим кодомusing System;
using System.Data;
using System.Web.Configuration;
using System.Data.SqlClient;
using System.Text;
public partial class DataSetRelationShips : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Извлекаем строку соединения с именем Northwind из файла web.config
string connectionString = WebConfigurationManager.
ConnectionStrings["Northwind"].ConnectionString;
// Создаем объект соединения
SqlConnection con = new SqlConnection(connectionString);
// Формируем строку SQL-запроса для заданных полей
string sqlProducts = "SELECT ProductName, Discontinued FROM Products";
// Создаем и настраиваем объект DataAdapter
SqlDataAdapter adapter = new SqlDataAdapter(sqlProducts, con);
// Создаем пустой объект DataSet набора данных
DataSet dataset = new DataSet();
// Выполняем запрос к БД с автоматическим
// открытием и закрытием соединения
try
{
// Добавить в DataSet данные с именованной
// меткой ProdTable из таблицы Products
adapter.Fill(dataset, "ProdTable");
}
catch
{
throw new ApplicationException("Ошибка данныx.");
}
// Получить по дополнительному условию
// массив продуктов, имеющих скидки
DataRow[] matchRows = dataset.Tables["ProdTable"].
Select("Discontinued <> 0"); // Дополнительное условие
// Выбрать имена продуктов со скидками
StringBuilder htmlStr = new StringBuilder("");
htmlStr.Append("<ol>"); // Открыли нумерованный список HTML
foreach (DataRow row in matchRows)
{
htmlStr.Append("<li>"); // Элемент маркированного списка HTML
htmlStr.Append(row["ProductName"].ToString()); // Имя поля
htmlStr.Append("</li>");
}
htmlStr.Append("</ol>"); // Закрыли нумерованный список HTML
// Отображаем полученные данные пользователю
lblInfo.Text = "<h2>Список продуктов,<br />имеющих скидки</h2>";
lblInfo.Text += htmlStr.ToString();
}
}
Приведенный код примера достаточно прост. Из данных, загруженных в по
Исполните страницу DataTableSelect.aspx, чтобы получить следующий результатСписок продуктов, имеющих скидки
Иногда более удобно не самому формировать HTML-вывод для изъятых из базы автономных данных, как мы это делали до сих пор, а воспользоваться специальным механизмом . Он автоматически формирует HTML-таблицы, в ячейки которых выводит данные, загруженные в набор данных . Порядок привязки набора данных к экземпляру GridView1 класса следующий:
GridView1.DataSource = dataset;
GridView1.DataMember = "TableLabel";
или сразу во все элементы отображения страницыGridView1.DataBind(); или Page.DataBind();
Если мы вызовем Page.DataBind(), то он пройдет по всем элементам управления страницы, поддерживающих привязку данных, и для каждого вызовет метод DataBind().
Приведем пример страницы , в которой загрузим и отобразим пользователю первые пять строк таблицы Employees учебной базы данных Northwind.
Добавьте к приложению WebSite8 новую страницу с раздельным кодом и именем GridViewEmployees.aspx. Назначьте эту страницу стартовой
Поместите на страницу из вкладки Data панели Toolbox элемент управления GridView с именем GridView1
Откройте на редактирование файл поддержки GridViewEmployees.aspx.cs и заполните его следующим кодом(рис ) Код файла GridViewEmployees.aspx.csusing System;
using System.Data;
using System.Web.Configuration;
using System.Data.SqlClient;
public partial class GridViewEmployees : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Содать Connection, DataAdapter и DataSet
string connectionString = WebConfigurationManager.
ConnectionStrings["Northwind"].ConnectionString;
SqlConnection con = new SqlConnection(connectionString);
string sql =
"SELECT TOP 5 EmployeeID, TitleOfCourtesy, LastName, "
+ "FirstName FROM Employees";
SqlDataAdapter adapter = new SqlDataAdapter(sql, con);
DataSet dataset = new DataSet();
adapter.Fill(dataset, "EmployeesTable");
// Привязать данные к GridView1 для отображения
GridView1.DataSource = dataset;
GridView1.DataMember = "EmployeesTable";
GridView1.DataBind();
}
}
Исполните страницу GridViewEmployees.aspx, чтобы получить следующий результат| EmployeeID | TitleOfCourtesy | ||
|---|---|---|---|
| 1 | Ms. | Davolio | Nancy |
| 2 | Dr. | Fuller | Andrew |
| 3 | Ms. | Leverling | Janet |
| 4 | Mrs. | Peacock Margaret | |
| 5 | Mr. Buchanan | Steven |
К элементу отображения можно привязать сразу конкретную таблицу из набора данных. В этом случае строки привязки будут выглядеть так (страница GridViewEmployees1.aspx )
// Привязать данные к GridView1 для отображения GridView1.DataSource = dataset.Tables["EmployeesTable"]; GridView1.DataBind();
Более того, существует класс DataView, который является представлением класса DataTable, с помощью которого можно предварительно отсортировать или отфильтровать данные перед привязкой к элементу управления для показа пользователю.
Приведем пример страницы, в которой используем три разных представления одной и той же таблицы в наборе данных.
Скопируйте страницу GridViewEmployees.aspx и дайте ей имя GridViewDataView.aspxПри копировании не забудьте на странице в директиве @Page исправить параметр а в файле поддержки переопределить имя класса на GridViewDataView
Поместите на страницу дополнительные элементы управления GridView так, чтобы они располагались друг за другом по вертикали в порядке GridView1, GridView2, GridView3
Вставьте перед каждым элементом строку-заголовок<h2>Несортированные данные</h2><h2>Сортированы по полю FirstName </h2><h2>Сортированы по полю LastName </h2>Интерфейс страницы на

Отредактируйте файл поддержки страницы следующим образом(рис ) Код файла GridViewDataView.aspx.cs using System;
using System.Data;
using System.Web.Configuration;
using System.Data.SqlClient;
public partial class GridViewDataView : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Содать Connection, DataAdapter и DataSet
string connectionString = WebConfigurationManager.
ConnectionStrings["Northwind"].ConnectionString;
SqlConnection con = new SqlConnection(connectionString);
string sql =
"SELECT TOP 5 EmployeeID, TitleOfCourtesy, LastName, "
+ "FirstName FROM Employees";
SqlDataAdapter adapter = new SqlDataAdapter(sql, con);
DataSet dataset = new DataSet();
adapter.Fill(dataset, "EmployeesTable");
// Привязать данные к GridView1 для отображения
// без сортировки как они есть
GridView1.DataSource = dataset.Tables["EmployeesTable"];
// Скопировать данные в экземпляр класса DataView,
// отсортировать по полю FirstName, затем привязать
DataView view2 = new DataView(dataset.Tables["EmployeesTable"]);
view2.Sort = "FirstName";
GridView2.DataSource = view2;
// Скопировать данные в экземпляр класса DataView,
// отсортировать по полю FirstName, затем привязать
DataView view3 = new DataView(dataset.Tables["EmployeesTable"]);
view3.Sort = "LastName";
GridView3.DataSource = view3;
// Загрузить привязанные данные во все элементы отображения GridView
Page.DataBind();
}
}
Исполните страницу GridViewDataView.aspx, чтобы получить следующий результатНесортированные данные
| EmployeeID | TitleOfCourtesy | ||
|---|---|---|---|
| 1 | Ms. | Davolio | Nancy |
| 2 | Dr. | Fuller | Andrew |
| 3 | Ms. | Leverling | Janet |
| 4 | Mrs. | Peacock | Margaret |
| 5 | Mr. | Buchanan | Steven |
Сортированы по полю FirstName
| EmployeeID | TitleOfCourtesy | ||
|---|---|---|---|
| 2 | Dr. | Fuller | Andrew |
| 3 | Ms. | Leverling | Janet |
| 4 | Mrs. | Peacock | Margaret |
| 1 | Ms. | Davolio | Nancy |
| 5 | Mr. | Buchanan | Steven |
Сортированы по полю LastName
| EmployeeID | TitleOfCourtesy | ||
|---|---|---|---|
| 5 | Mr. | Buchanan | Steven |
| 1 | Ms. | Davolio | Nancy |
| 2 | Dr. | Fuller | Andrew |
| 3 | Ms. | Leverling | Janet |
| 4 | Mrs. | Peacock | Margaret |
Объект DataView можно использовать для фильтрации извлеченных автономных данных перед их отображением пользователю. Для этого нужно задать объекту значение свойства RowFilter, которое использует те же операторы логических условий, что и в
| Операция | Описание |
|---|---|
<, >, <=, >= |
Сравнение числовых или |
<>, = |
Проверка на эквивалентность |
NOT |
|
BETWEEN |
Указывает диапазон включительно. Например, выбирает строки, у которых значение столбца находится в диапазоне 5-15 включительно |
IS NULL |
Проверяет столбец на нулевое значение |
IN(a, b, c) |
Краткая форма операции OR с одним и тем же полем. Проверяет эквивалентность значения столбца любому из перечисленных значений списка нужной длины, например a, b, c |
LIKE |
Проверяет соответствие строкового значения шаблону |
+ |
|
- |
Вычитает одно числовое значение из другого |
* |
Перемножает два числовых значения |
/ |
Делит одно числовое значение на другое |
% |
Вычисляет модуль - |
AND |
Логическое |
OR |
Логическое |
Приведем пример страницы, в которой имеются три элемента . Каждый из них привязан через DataView к одним и тем же данным DataTable, но с разными установками фильтрации.
Создайте копию страницы GridViewDataView.aspx с именем DataViewFiltered.aspx и назначьте ее стартовой
В странице DataViewFiltered.aspx выполните следующие изменения@Page установите новое значение атрибута Inherits ="DataViewFiltered"<h2> на <h3> со следующим содержимым<h3> Фильтровать продукт Chocolade<br /> (RowFilter = "ProductName = 'Chocolade'") </h3>
<h3> Фильтровать продукты, которых нет в заказах и на складе<br /> (RowFilter = "UnitsInStock = 0 AND UnitsOnOrder = 0") </h3>
<h3> Фильтровать продукты, чье название начинается с буквы P<br /> (RowFilter = "ProductName LIKE 'P%'") </h3>
В файле поддержки DataViewFiltered.aspx.cs установите новое DataViewFiltered и наполните файл следующим кодом(рис ) Код файла DataViewFiltered.aspx.csusing System;
using System.Data;
using System.Web.Configuration;
using System.Data.SqlClient;
public partial class DataViewFiltered : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Содать Connection, DataAdapter и DataSet
string connectionString = WebConfigurationManager.
ConnectionStrings["Northwind"].ConnectionString;
SqlConnection con = new SqlConnection(connectionString);
string sql =
"SELECT ProductID, ProductName, UnitsInStock, UnitsOnOrder, "
+ "Discontinued FROM Products";
SqlDataAdapter adapter = new SqlDataAdapter(sql, con);
DataSet dataset = new DataSet();
adapter.Fill(dataset, "ProductsTable");
// Фильтровать продукт Chocolade
DataView view1 = new DataView(dataset.Tables["ProductsTable"]);
view1.RowFilter = "ProductName = 'Chocolade'";
GridView1.DataSource = view1;
// Фильтровать продукты, которых нет в заказах и на складе
DataView view2 = new DataView(dataset.Tables["ProductsTable"]);
view2.RowFilter = "UnitsInStock = 0 AND UnitsOnOrder = 0";
GridView2.DataSource = view2;
// Фильтровать продукты, чье название начинается с буквы P
DataView view3 = new DataView(dataset.Tables["ProductsTable"]);
view3.RowFilter = "ProductName LIKE 'P%'";
GridView3.DataSource = view3;
// Загрузить привязанные данные во все элементы отображения GridView
this.DataBind();
}
}
Запустите страницу DataViewFiltered.aspx и получите следующий результатФильтровать продукт Chocolade (RowFilter = "ProductName = 'Chocolade'")
| ProductID | ProductName | UnitsInStock | UnitsOnOrder | |
|---|---|---|---|---|
| 48 | Chocolade | 15 | 70 | ![]() |
Фильтровать продукты, которых нет в заказах и на складе (RowFilter = "UnitsInStock = 0 AND UnitsOnOrder = 0")
| ProductID | ProductName | UnitsInStock | UnitsOnOrder | |
|---|---|---|---|---|
| 5 | Chef Anton's Gumbo |
0 | 0 | ![]() |
| 17 | Alice Mutton | 0 | 0 | ![]() |
| 29 | Th№ringer Rostbratwurst | 0 | 0 | ![]() |
| 53 | Perth Pasties | 0 | 0 | ![]() |
Фильтровать продукты, чье название начинается с буквы P (RowFilter = "ProductName LIKE 'P%'")
| ProductID | ProductName | UnitsInStock | UnitsOnOrder | |
|---|---|---|---|---|
| 16 | Pavlova | 29 | 0 | ![]() |
| 53 | Perth Pasties | 0 | 0 | ![]() |
| 55 | Pтtщ chinois | 115 | 0 | ![]() |
Класс System.Data.DataView также имеет свойство RowStateFilter, которое можно использовать для фильтрации данных так, чтобы отображались только строки, имеющие определенное состояние (вставленные, помеченные на удаление, модифицированные или неизмененные). По умолчанию это свойство установлено на отображение всех строк, кроме помеченных на удаление.
Класс DataView может выполнять и более сложную фильтрацию на основе таблиц, связанных отношением "Главный-подчиненный". Например, можно отобразить категории, каждая из которых содержит более 20 наименований продуктов, или отобразить заказчиков, сделавших определенное количество покупок.
Продемонстрируем эту возможность на примере двух таблиц: и учебной базы Northwind.
Сделайте копию страницы DataSetRelationShips.aspx и назовите ее DataViewRelation.aspx
Исправьте значения атрибута Inherits в @Page страницы и
Удалите со страницы DataViewRelation.aspx текстовую метку lblInfo и поместите вместо нее заголовочный <h2>Категории с продуктами дороже $50</h2>
Поместите после заголовочного GridView из вкладки Data панели Toolbox
Скорректируйте файл поддержки страницы DataViewRelation.aspx.cs следующим образом(рис ) Код файла DataViewRelation.aspx.csusing System;
using System.Data;
using System.Web.Configuration;
using System.Data.SqlClient;
using System.Text;
public partial class DataSetRelationShips : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Извлекаем строку соединения с именем Northwind из файла web.config
string connectionString = WebConfigurationManager.
ConnectionStrings["Northwind"].ConnectionString;
// Создаем объект соединения
SqlConnection con = new SqlConnection(connectionString);
// Формируем строки SQL-запросов
string sqlCategories = "SELECT CategoryID, CategoryName FROM Categories";
string sqlProducts = "SELECT ProductName, CategoryID, UnitPrice FROM Products";
// Создаем объект DataAdapter
SqlDataAdapter adapter = new SqlDataAdapter(sqlCategories, con);
// Создаем пустой объект DataSet набора данных
DataSet dataset = new DataSet();
// Выполняем два запроса к БД с открытием
// и закрытием соединения вручную.
// Возможные исключения не обрабатываем, а просто подавляем
try
{
con.Open();
// Наполнить DataSet данными из таблицы Categories
// с именованной меткой CatTable
adapter.Fill(dataset, "CatTable");
// Сменить команду и добавить в DataSet данные
// с именованной меткой ProdTable из таблицы Products
adapter.SelectCommand.CommandText = sqlProducts;
adapter.Fill(dataset, "ProdTable");
}
finally
{
con.Close();
}
// Определение отношения между извлеченными в DataSet
// именованными данными CatTable и ProdTable
DataRelation relation = new DataRelation(
"CatProd", // Имя отношения
dataset.Tables["CatTable"].Columns["CategoryID"], // Родительская таблица
dataset.Tables["ProdTable"].Columns["CategoryID"] // Дочерняя таблица
);
// Добавление отношения в коллекцию отношений DataSet
dataset.Relations.Add(relation);
// Создаем объект DataView, в который загружаем данные CatTable
DataView view1 = new DataView(dataset.Tables["CatTable"]);
// Устанавливаем фильтр для отображения только категорий продуктов,
// цена которых в связанной таблице продуктов удовлетворяет условию
// "Самый дорогой продукт дороже 50"
view1.RowFilter = "MAX(Child(CatProd).UnitPrice) > 50";
// Показываем отфильтрованные данные пользователю
GridView1.DataSource = view1;
GridView1.DataBind();
}
}
Назначьте страницу DataViewRelation.aspx стартовой и выполните ееДолжен получиться следующий результат
Категории с продуктами дороже $50
| CategoryID | CategoryName |
|---|---|
| 1 | Beverages |
| 3 | Confections |
| 4 | Dairy |
| 6 | Meat/Poultry |
| 7 | Produce |
| 8 | Seafood |
В фильтре мы установили условие, чтобы показать пользователю только те записи в UnitPrice>50. Это означает, что выводятся категории продуктов, в которых хотя бы один продукт дороже $50.
Таким образом, класс позволяет одноразово загрузить нужные данные из источника, а затем в отсоединенном автономном режиме что-то с ними делать. До сих пор мы показывали пользователю все автономные данные, полученные по
DataSet.Tables["TableName"].Select("Дополнительное_условие")
Показывали, также, данные с условием, наложенным в свойстве DataView.RowFilter вспомогательного объекта DataView.
Теперь рассмотрим вопрос, как в дополнение к полям, извлеченным в набор данных из физического
Чтобы создать вычисляемый столбец в , необходимо отдельно создать новый объект класса DataColumn, установить формулу в его свойстве и добавить этот столбец в коллекцию объекта
dataset.Tables["TableName"].Columns.Add(datacolumn)
Рассмотрим пример, в котором создадим столбец, объединяющий фамилию и имя каждого служащего из таблицы Employees учебной базы данных Northwind.
Создайте копию файла TestDataSet.aspx с именем ExpressionColumns.aspx и назначьте ее стартовой
Откройте на редактирование файл поддержки ExpressionColumns.aspx.cs и отредактируйте его так(рис ) Код файла ExpressionColumns.aspx.cs using System;
using System.Data;
using System.Web.Configuration;
using System.Data.SqlClient;
using System.Text;
public partial class ExpressionColumns : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Извлекаем строку соединения с именем Northwind из файла web.config
string connectionString = WebConfigurationManager.
ConnectionStrings["Northwind"].ConnectionString;
// Формируем строку SQL для выборки всех данных таблицы Employees
string commandString = "SELECT * FROM Employees";
// Создаем и настраиваем экземпляр класса SqlDataAdapter
SqlDataAdapter adapter =
new SqlDataAdapter(commandString, connectionString);
// Создаем объект DataSet результирующего набора данных
DataSet dataset = new DataSet();
// Безопасно заполняем данными объект DataTable с произвольным
// именем, например "EmployeesResult", созданного объекта DataSet
try
{
adapter.Fill(dataset, "EmployeesResult");
}
catch
{
throw new ApplicationException("Ошибка данныx.");
}
// Создаем именованный столбец и добавляем к таблице в DataSet
string strExpr =
"'Сотрудник ' + TitleOfCourtesy + ' ' + LastName + ', ' + FirstName";
DataColumn column = new DataColumn("FullName", typeof(string), strExpr);
dataset.Tables["EmployeesResult"].Columns.Add(column);
// Перебираем все объекты DataRow с полученным записами
StringBuilder htmlStr = new StringBuilder("");
foreach (DataRow dr in dataset.Tables["EmployeesResult"].Rows)
{
htmlStr.Append("<li>");
// Существующий столбец
htmlStr.Append(dr["EmployeeID"].ToString() + ") ");
htmlStr.Append("<b>");
// Новый столбец
htmlStr.Append(dr["FullName"].ToString());
htmlStr.Append("</b>");
htmlStr.Append("</li>");
}
// Отображаем полученные данные
lblInfo.Text = "<h2>Список сотрудников</h2>";
lblInfo.Text += htmlStr.ToString();
}
}
Выполните страницу ExpressionColumns.aspx и получите следующий результатСписок сотрудников
Можно создать в вычисляемые столбцы для связанных строк. Например, можно добавить в CatTable столбец, показывающий количество связанных строк ProdTable. В этом случае нужно определить отношение объектом DataRelation и использовать .
Приведем пример, в котором создается три вычисляемых столбца со своей агрегатной функцией и используется отношение таблиц.
Создайте копию страницы DataViewRelation.aspx с именем ExpressionColumnsRelation.aspx и назначьте ее стартовой
Исправьте значения атрибута Inherits в @Page страницы и
Измените на странице заголовочный <h2>Добавление вычисляемых столбцов</h2>
Откройте кодовый файл ExpressionColumnsRelation.aspx.cs на редактирование и откорректируйте его так(рис ) Код файла ExpressionColumnsRelation.aspx.csusing System;
using System.Data;
using System.Web.Configuration;
using System.Data.SqlClient;
using System.Text;
public partial class ExpressionColumnsRelation : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Извлекаем строку соединения с именем Northwind из файла web.config
string connectionString = WebConfigurationManager.
ConnectionStrings["Northwind"].ConnectionString;
// Создаем объект соединения
SqlConnection con = new SqlConnection(connectionString);
// Формируем строки SQL-запросов
string sqlCategories = "SELECT CategoryID, CategoryName FROM Categories";
string sqlProducts = "SELECT ProductName, CategoryID, UnitPrice FROM Products";
// Создаем объект DataAdapter
SqlDataAdapter adapter = new SqlDataAdapter(sqlCategories, con);
// Создаем пустой объект DataSet набора данных
DataSet dataset = new DataSet();
// Выполняем два запроса к БД с открытием
// и закрытием соединения вручную.
// Возможные исключения не обрабатываем, а просто подавляем
try
{
con.Open();
// Наполнить DataSet данными из таблицы Categories
// с именованной меткой CatTable
adapter.Fill(dataset, "CatTable");
// Сменить команду и добавить в DataSet данные
// с именованной меткой ProdTable из таблицы Products
adapter.SelectCommand.CommandText = sqlProducts;
adapter.Fill(dataset, "ProdTable");
}
finally
{
con.Close();
}
// Определение отношения между извлеченными в DataSet
// именованными данными CatTable и ProdTable
DataRelation relation = new DataRelation(
"CatProd", // Имя отношения
dataset.Tables["CatTable"].Columns["CategoryID"], // Родительская таблица
dataset.Tables["ProdTable"].Columns["CategoryID"] // Дочерняя таблица
);
// Добавление отношения в коллекцию отношений DataSet
dataset.Relations.Add(relation);
// Создать вычисляемые столбцы и добавить их в DataSet
DataColumn count = new DataColumn("Кол. продуктов", typeof(int),
"COUNT(Child(CatProd).CategoryID)");
dataset.Tables["CatTable"].Columns.Add(count);
DataColumn max = new DataColumn("Самый дорогой продукт", typeof(decimal),
"MAX(Child(CatProd).UnitPrice)");
dataset.Tables["CatTable"].Columns.Add(max);
DataColumn min = new DataColumn("Самый дешевый продукт", typeof(decimal),
"MIN(Child(CatProd).UnitPrice)");
dataset.Tables["CatTable"].Columns.Add(min);
// Меняем названия заголовков столбцов на русский язык
dataset.Tables["CatTable"].Columns["CategoryID"].ColumnName = "№ п/п";
dataset.Tables["CatTable"].Columns["CategoryName"].ColumnName = "Наименование категории";
// Показываем данные пользователю
GridView1.DataSource = dataset.Tables["CatTable"];
GridView1.DataBind();
}
}
Исполните страницу ExpressionColumnsRelation.aspx и получите следующий результатДобавление вычисляемых столбцов
| № п/п | Наименование категории | Кол. продуктов | Самый дорогой продукт | Самый дешевый продукт |
|---|---|---|---|---|
| 1 | Beverages | 12 | 263,5000 | 4,5000 |
| 2 | Condiments | 12 | 43,9000 | 10,0000 |
| 3 | Confections | 13 | 81,0000 | 9,2000 |
| 4 | Dairy |
10 | 55,0000 | 2,5000 |
| 5 | 7 | 38,0000 | 7,0000 | |
| 6 | Meat/Poultry | 6 | 123,7900 | 7,4500 |
| 7 | Produce | 5 | 53,0000 | 10,0000 |
| 8 | Seafood | 12 | 62,5000 | 6,0000 |
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.