Класс DataView

117

Класс DataView определяет представление объекта DataTable — другими словами, представление данных в DataTable, которое может включать пользовательские настройки фильтрации и сортировки. Для конфигурирования этих настроек в DataView предусмотрены такие свойства, как Sort и RowFilter. Эти свойства позволяют выбрать данные, которые должны быть видимы в представлении. Однако они не затронут реальные данные DataTable. Например, если вы отфильтруете таблицу так, чтобы скрыть определенные строки, то эти строки останутся в DataTable, но не будут доступны через DataView.

Класс DataView удобен, в частности, в сценариях привязки данных. Он позволяет показать только подмножество общего набора данных таблицы, без необходимости обрабатывать или изменять данные, если они нужны вам для других задач.

Каждый объект DataTable имеет ассоциированный с ним объект DataView по умолчанию, хотя допускается создавать множество объектов DataView для представления разных видов одной и той же таблицы. DataView по умолчанию представлен свойством DataTable.DefaultView.

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

Сортировка с помощью DataView

В следующем примере используется страница с тремя элементами управления GridView. Когда эта страница загружается, все элементы привязываются к одной DataTable. Однако она использует три разных представления, каждое из которых сортирует результат по разным полям:


<!-- Разметка страницы -->
<body>
    <form id="form1" runat="server">
        <asp:Label ID="Label1" runat="server" Text="<h3>Исходная таблица</h3>" />
        <asp:GridView ID="GridView1" runat="server"></asp:GridView>
        <asp:Label ID="Label2" runat="server" Text="<h3>Сортировка по столбцу LastName</h3>" />
        <asp:GridView ID="GridView2" runat="server"></asp:GridView>
        <asp:Label ID="Label3" runat="server" Text="<h3>Сортировка по столбцу FirstName</h3>" />
        <asp:GridView ID="GridView3" runat="server"></asp:GridView>
    </form>
</body>
protected void Page_Load(object sender, EventArgs e)
 {
        // Строка подключения из файла web.config
        string connectionString = 
            WebConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;
        SqlConnection connect = new SqlConnection(connectionString);

        string cmd = "SELECT TOP 5 EmployeeID, LastName, FirstName, BirthDate FROM Employees";
        SqlDataAdapter adapter = new SqlDataAdapter(cmd, connect);

        DataSet dataset = new DataSet();
        adapter.Fill(dataset, "Employees");

        // Привязать исходные данные к элементу GridView1
        GridView1.DataSource = dataset.Tables["Employees"];

        // Сортировать по фамилии и привязать к элементу GridView2
        DataView view2 = new DataView(dataset.Tables["Employees"]);
        view2.Sort = "LastName";
        GridView2.DataSource = view2;

        // Сортировать no имени и привязать к элементу GridView3
        DataView view3 = new DataView(dataset.Tables["Employees"]);
        view3.Sort = "FirstName";
        GridView3.DataSource = view3;

        // Скопировать данные из привязанных DataSet (DataView)
        Page.DataBind();
}

Код начинается с извлечения списка сотрудников в DataSet. На следующем шаге происходит наполнение элемента управления GridView с помощью привязки данных. Чтобы привязать первый из них, можно просто применить объект DataTable непосредственно, что заставит его использовать DataView по умолчанию и отобразить данные. Для двух других понадобится создать новый объект DataView, а затем явно использовать его свойство Sort.

Сортировка отображаемых данных заключается просто в присваивании свойству DataView.Sort корректного выражения сортировки. В данном примере сортировка выполняется в каждом представлении по значениям единственного поля, но также можно сортировать и нескольким полям, указывая список полей, разделенных запятыми. Вот пример:

view2.Sort = "LastName, FirstName";

Сортировка осуществляется в соответствии с типом данных столбца. Числовые столбцы и столбцы дат упорядочиваются от меньших значений к большим. Строковые столбцы сортируются в алфавитно-цифровом порядке, независимо от регистра, если свойство DataTable.CaseSensitive установлено в false (по умолчанию). Столбцы, содержащие двоичные данные, сортироваться не могут. С помощью атрибутов ASC или DESC сортировка производится в возрастающем или убывающем порядке:

view2.Sort = "LastName ASC, FirstName DESC";

Привязав экранные таблицы, необходимо инициировать процесс привязки данных, копирующий значения DataTable в элемент управления. Это можно сделать для каждого элемента отдельно или для всей страницы в целом — вызовом Page.DataBind(). На рисунке ниже показана результирующая страница:

Экранные таблицы, отсортированные разными способами

Фильтрация с помощью DataView

Элемент DataView можно также использовать для применения пользовательской фильтрации, чтобы отображать на экране только определенные строки. Для обеспечения этой возможности служит свойство RowFilter. Свойство RowFilter действует подобно конструкции WHERE в SQL-запросе. Используя его, результат можно ограничить с помощью логических операций (таких как <, > и =) и широкого диапазона критериев.

В таблице ниже перечислены наиболее часто используемые операции фильтрования:

Операции фильтрования
Операция Описание
<, >, <= и >=

Выполняют сравнение более чем одного значения. Эти сравнения могут быть числовыми (с данными числовых типов) или алфавитными сравнениями по словарю (со строковыми данными)

<> и =

Выполняют проверку на эквивалентность

NOT

Обращает логическое выражение. Может использоваться в сочетании с любой другой конструкцией

BETWEEN

Указывает включающий диапазон. Например, Units BETWEEN 5 AND 15 выбирает строки, у которых значение столбца Units находится в пределах от 5 до 15

IS NULL

Проверяет столбец на null-значение

IN (a,b,c)

Краткая форма операции OR с одним и тем же полем. Проверяет эквивалентность значения столбца любому из перечисленных значений (a,b,c)

LIKE

Выполняет проверку соответствия строкового значения шаблону

+

Складывает два числа или выполняет конкатенацию двух строк

-

Вычитает одно числовое значение из другого

*

Перемножает два числовых значения

/

Делит одно числовое значение на другое

%

Вычисляет модуль (остаток от деления одного числа на другое)

AND

Комбинирует более одной логической конструкции. Для отображения запись должна соответствовать всем критериям, объединенным с помощью AND

OR

Комбинирует более одной логической конструкции. Для отображения запись должна соответствовать хотя бы одному критерию из объединенных с помощью OR

Следующий пример страницы включает три элемента управления GridView. Каждый из них привязан к одной и той же DataTable, но с разными установками фильтрации:

protected void Page_Load(object sender, EventArgs e)
{
        // Строка подключения из файла web.config
        string connectionString = 
            WebConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;
        SqlConnection connect = new SqlConnection(connectionString);

        string cmd = "SELECT ProductID, ProductName, UnitsInStock, UnitsOnOrder, Discontinued FROM Products";
        SqlDataAdapter adapter = new SqlDataAdapter(cmd, connect);

        DataSet dataset = new DataSet();
        adapter.Fill(dataset, "Products");

        // Фильтровать товар Chocolade
        DataView view1 = new DataView(dataset.Tables["Products"]);
        view1.RowFilter = "ProductName = 'Chocolade'";
        GridView1.DataSource = view1;
        Label1.Text = @"<b>Filter = ""ProductName = 'Chocolade'""</b>";

        // Фильтровать товары, которых нет в заказах и на складе
        DataView view2 = new DataView(dataset.Tables["Products"]);
        view2.RowFilter = "UnitsInStock = 0 AND UnitsOnOrder = 0";
        GridView2.DataSource = view2;
        Label2.Text = @"<b>Filter = ""UnitsInStock = 0 AND UnitsOnOrder = 0""</b>";

        // Фильтровать товары, чье название начинается с буквы P
        DataView view3 = new DataView(dataset.Tables["Products"]);
        view3.RowFilter = "ProductName LIKE 'P%'";
        GridView3.DataSource = view3;
        Label3.Text = @"<b>Filter = ""ProductName LIKE 'P%'""</b>";

        // Скопировать данные из привязанных DataSet (DataView)
        Page.DataBind();
}

Запуск этой страницы приводит к заполнению трех экранных таблиц, как показано на рисунке:

Фильтрация таблиц

Расширенное фильтрование с отношениями

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

Чтобы создать такую строку фильтрующего выражения, понадобится скомбинировать два ингредиента:

Например, предположим, что объект DataSet заполнен таблицами Categories и Products, между которыми определено отношение по ключу CategoryID:

protected void Page_Load(object sender, EventArgs e)
{
        // Строка подключения из файла web.config
        string connectionString = 
            WebConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;
        SqlConnection connect = new SqlConnection(connectionString);

        string sqlCat = "SELECT CategoryID, CategoryName FROM Categories";
        string sqlProd = "SELECT ProductName, CategoryID, UnitPrice FROM Products";

        SqlDataAdapter adapter = new SqlDataAdapter(sqlCat, connect);
        DataSet dataset = new DataSet();
        adapter.Fill(dataset, "Categories");

        adapter.SelectCommand.CommandText = sqlProd;
        adapter.Fill(dataset, "Products");

        // Связать таблицы Categories и Products в DataSet
        DataRelation relation = new DataRelation("CatProds",
            dataset.Tables["Categories"].Columns["CategoryID"],
            dataset.Tables["Products"].Columns["CategoryID"]);

        // ...
}

Теперь можно фильтровать данные таблицы Categories с использованием выражения фильтрации, основанного на таблице Products. Например, предположим, что необходимо показать только те записи о категориях, для которых существует хотя бы один товар стоимостью более $80. Чтобы добиться этого, используется функция МАХ() наряду с именем отношения таблиц (CatProds). Вот как будет выглядеть необходимая строка фильтрации:

MAX(Child(CatProds).UnitPrice) > 80

Ниже показан код, применяющий эту строку к DataView:

protected void Page_Load(object sender, EventArgs e)
{
        // ...
        dataset.Relations.Add(relation);

        // Фильтровать категории, в которых есть товары дороже $50
        DataView view = new DataView(dataset.Tables["Categories"]);
        view.RowFilter = "MAX(Child(CatProds).UnitPrice) > 80";
        GridView1.DataSource = view;

        // Скопировать данные из привязанных DataSet (DataView)
        Page.DataBind();
}

В результате элемент GridView отобразит только те категории, в которых есть товары дороже $80:

Фильтрация данных с отношениями

Вычисляемые столбцы

В дополнение к полям, извлеченным из источника данных, можно добавить вычисляемые столбцы. Вычисляемые столбцы игнорируются при извлечении и обновлении данных. Вместо этого они представляют значения, которые вычисляются на основе комбинации существующих значений. Чтобы создать вычисляемый столбец, нужно просто создать новый объект DataColumn (указав его имя и тип) и установить его свойство Expression. Затем этот объект DataColumn следует добавить в коллекцию Columns объекта DataTable с помощью метода Add().

В качестве примере рассмотрим столбец, использующий конкатенацию строк для комбинирования имени и фамилии в одном поле:

DataColumn fullName = new DataColumn( "FullName", typeof(string),
	"LastName + FirstName"); 
        
	dataset.Tables["Employees"].Columns.Add(fullName);

Разумеется, вы также можете выполнить запрос, создающий вычисляемые поля. Однако такой подход создает больше трудностей при последующем обновлении источника данных и прибавляет ему работы. По этой причине часто лучше создавать вычисляемые столбцы в DataSet.

Можно создавать вычисляемые столбцы, которые включают информацию из связанных строк, например, добавить в таблицу Categories столбец, показывающий количество связанных строк таблицы Products. В этом случае нужно сначала определить отношение с помощью объекта DataRelation. Также необходимо использовать агрегатную функцию SQL, такую как AVG(), MAX(), MIN() или COUNT().

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

protected void Page_Load(object sender, EventArgs e)
{
        // Строка подключения из файла web.config
        string connectionString = 
            WebConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;
        SqlConnection connect = new SqlConnection(connectionString);

        string sqlCat = "SELECT CategoryID, CategoryName FROM Categories";
        string sqlProd = "SELECT ProductName, CategoryID, UnitPrice FROM Products";

        SqlDataAdapter adapter = new SqlDataAdapter(sqlCat, connect);
        DataSet dataset = new DataSet();
        adapter.Fill(dataset, "Categories");

        adapter.SelectCommand.CommandText = sqlProd;
        adapter.Fill(dataset, "Products");

        // Связать таблицы Categories и Products в DataSet
        DataRelation relation = new DataRelation("CatProds",
            dataset.Tables["Categories"].Columns["CategoryID"],
            dataset.Tables["Products"].Columns["CategoryID"]);

        dataset.Relations.Add(relation);

        // Создать вычисляемые столбцы
        DataColumn count = new DataColumn(
         "Кол-во связанных продуктов", typeof(int), "COUNT(Child(CatProds).CategoryID)");
        DataColumn max = new DataColumn(
          "Самый дорогой продукт: стоимость", typeof(decimal), "MAX(Child(CatProds).UnitPrice)");
        DataColumn min = new DataColumn(
          "Самый дешевый продукт: стоимость", typeof(decimal), "MIN(Child(CatProds).UnitPrice)");

        // Добавить столбцы
        dataset.Tables["Categories"].Columns.Add(count);
        dataset.Tables["Categories"].Columns.Add(max);
        dataset.Tables["Categories"].Columns.Add(min);

        // Отобразить данные
        GridView1.DataSource = dataset.Tables["Categories"];
        Page.DataBind();
}

На рисунке ниже показана результирующая страница:

Отображение вычисляемых столбцов

Имейте в виду, что эти примеры просто демонстрируют удобные способы фильтрации и агрегирования данных. Эти операции являются только частью правильного представления данных. Другая часть — это их корректное форматирование. В следующих статьях вы узнаете намного больше о GridView, так что сможете отображать денежные значения в соответствующем формате и настраивать другие детали отображения вроде цвета, размера, порядка следования столбцов и шрифтов. Например, установив формат, вы можете изменить 4.5000 на более разумное отображаемое значение — $4.50.

Пройди тесты
Лучший чат для C# программистов