
Первый GridView: выводим таблицу из SQL Server в ASP.NET
Минимальный рабочий пример: кнопка на странице, запрос к базе Northwind и таблица GridView с результатом. Плюс то, что обычно опускают в «hello world»: Using, web.config и IsPostBack.
Что понадобится
Для примера возьмём учебную базу Northwind, установленную на SQL Server Express. В ней есть небольшая таблица Categories из трёх полей: идентификатор, название и описание категории. Этого достаточно, чтобы увидеть весь путь данных от базы до браузера и не утонуть в деталях.
Схема работы всегда одна и та же: открыть соединение с базой, выполнить запрос, сложить результат в объект в памяти и отдать его GridView. Для SQL Server в .NET есть специализированный провайдер System.Data.SqlClient, он работает быстрее универсального OleDb и поддерживает все возможности сервера. Классы DataSet и DataTable лежат в пространстве имён System.Data.
Чтобы не писать каждый раз полные имена вроде System.Data.SqlClient.SqlConnection, подключим оба пространства имён директивой Imports в начале файла кода.
Разметка страницы
На страницу кладём кнопку и пустой GridView. Ни колонок, ни стилей задавать не будем: при AutoGenerateColumns, который включён по умолчанию, грид сам создаст по колонке на каждое поле результата и возьмёт имена полей в качестве заголовков. Для первого знакомства это удобно, в реальных проектах колонки обычно описывают явно.
Свойство EmptyDataText стоит задать сразу. Если запрос вернёт ноль строк, GridView по умолчанию не выводит ничего, и пользователь видит пустое место без объяснений.
<%@ Page Language="VB" AutoEventWireup="false"
CodeFile="Default.aspx.vb" Inherits="_Default" %>
<!DOCTYPE html>
<html lang="ru">
<head runat="server">
<title>Категории</title>
</head>
<body>
<form id="form1" runat="server">
<asp:Button ID="btnLoadGrid" runat="server" Text="Загрузить" />
<asp:GridView ID="GridView1" runat="server"
EmptyDataText="Категорий не найдено" />
</form>
</body>
</html>Строка подключения: место ей в web.config
Во многих старых примерах строку подключения пишут прямо в коде. Это работает, но при переносе на другой сервер приходится перекомпилировать проект, а пароль от базы оказывается в исходниках. Правильное место для неё: раздел connectionStrings в web.config. Оттуда её читает ConfigurationManager, а администратор может поменять сервер без участия программиста.
Trusted_Connection=True означает вход под учётной записью Windows, от имени которой работает пул приложений IIS. Если сайт получает ошибку входа, причина почти всегда в том, что у этой учётной записи нет прав на базу, а не в коде.
<configuration>
<connectionStrings>
<add name="Northwind"
connectionString="Server=localhost\SQLEXPRESS;Database=Northwind;Trusted_Connection=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>Загрузка данных по шагам
Теперь код обработчика кнопки. Последовательность действий стоит запомнить, она повторяется почти в каждой странице Web Forms с данными:
- Создаём SqlConnection со строкой подключения из web.config.
- Создаём SqlDataAdapter с текстом запроса и этим соединением.
- Вызываем Fill: адаптер сам откроет соединение, выполнит запрос, заполнит DataTable и закроет соединение.
- Присваиваем DataTable свойству DataSource у GridView.
- Вызываем DataBind, именно в этот момент грид строит строки таблицы.
Imports System.Data
Imports System.Data.SqlClient
Imports System.Configuration
Partial Class _Default
Inherits System.Web.UI.Page
Protected Sub btnLoadGrid_Click(sender As Object, e As EventArgs) _
Handles btnLoadGrid.Click
Dim cs = ConfigurationManager.ConnectionStrings("Northwind").ConnectionString
Dim table As New DataTable()
' Using гарантирует закрытие соединения даже при исключении
Using cn As New SqlConnection(cs),
da As New SqlDataAdapter(
"SELECT CategoryID, CategoryName, Description FROM Categories", cn)
da.Fill(table)
End Using
GridView1.DataSource = table
GridView1.DataBind()
End Sub
End ClassDataSet или DataTable
В примерах начала 2000-х результат почти всегда складывали в DataSet, а потом брали GridView1.DataSource = ds.Tables(0). DataSet это контейнер для нескольких таблиц со связями между ними, он полезен, когда запрос возвращает несколько наборов строк. Для одного SELECT достаточно DataTable: меньше лишних объектов и понятнее код.
Можно обойтись и без адаптера: SqlCommand.ExecuteReader вернёт SqlDataReader, который тоже годится в DataSource. Это самый быстрый способ, но у ридера есть ограничение: он читает данные один раз и вперёд. Для сортировки и постраничного вывода в памяти DataTable удобнее.
Page_Load и IsPostBack
Часто данные хотят показать сразу при открытии страницы, без кнопки. Тогда загрузку переносят в Page_Load, и здесь новички делают классическую ошибку: перечитывают данные на каждый постбэк. В результате любое нажатие кнопки на странице заново запрашивает базу, а при редактировании строки введённые значения затираются свежей привязкой.
Решение: загружать данные только при первом открытии, проверяя If Not IsPostBack. На постбэках GridView восстановит своё содержимое из ViewState. Если же данные нужно обновить после изменения, вызовите метод привязки явно в конце соответствующего обработчика.
Когда этот пример заработает, следующий логичный шаг: описать колонки вручную через BoundField и TemplateField, добавить редактирование, сортировку и постраничный вывод. Об этом в соседних статьях раздела.
Как это делают сегодня
Вопросы и ответы
Почему GridView ничего не показывает, хотя ошибок нет?
Чаще всего забыт вызов DataBind после установки DataSource. Второй вариант: запрос вернул ноль строк, а EmptyDataText не задан, поэтому таблица просто не выводится.
Нужно ли вызывать Open перед Fill?
Нет. SqlDataAdapter.Fill сам открывает закрытое соединение и закрывает его после работы. Если же вы открыли соединение вручную, Fill оставит его открытым, и закрывать придётся самостоятельно.
Где взять базу Northwind?
Скрипт instnwnd.sql публикует Microsoft в репозитории sql-server-samples на GitHub. Его достаточно выполнить в SQL Server Management Studio на любом экземпляре, включая Express и LocalDB.