Первый GridView: выводим таблицу из SQL Server в ASP.NET

РазделGridViewУровеньНовичок Чтение7 минОпубликовано ТегиASP.NETGridViewADO.NETSQL Server

Минимальный рабочий пример: кнопка на странице, запрос к базе Northwind и таблица GridView с результатом. Плюс то, что обычно опускают в «hello world»: Using, web.config и IsPostBack.

Главное. Связка SqlConnection, SqlDataAdapter, DataTable и DataBind покрывает большинство задач вывода данных в Web Forms. Строку подключения держите в web.config, соединение заворачивайте в Using, а в Page_Load не забывайте про 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 по умолчанию не выводит ничего, и пользователь видит пустое место без объяснений.

Default.aspxASPX
<%@ 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. Если сайт получает ошибку входа, причина почти всегда в том, что у этой учётной записи нет прав на базу, а не в коде.

web.configXML
<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, именно в этот момент грид строит строки таблицы.
Default.aspx.vbVB.NET
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 Class
Если открываете соединение вручную через Open, закрывайте его в Finally или используйте Using. Незакрытые соединения быстро исчерпывают пул, и сайт начинает падать с таймаутом под нагрузкой.

DataSet или 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, добавить редактирование, сортировку и постраничный вывод. Об этом в соседних статьях раздела.

Как это делают сегодня

В современных проектах на .NET 8 вместо System.Data.SqlClient используют пакет Microsoft.Data.SqlClient, а данные получают через EF Core или Dapper в виде типизированных объектов, а не DataTable. Выводят их в Razor Pages обычным циклом по таблице или в Blazor через компонент QuickGrid. Строку подключения хранят в appsettings.json и секретах окружения, а не в коде.

Вопросы и ответы

Почему GridView ничего не показывает, хотя ошибок нет?

Чаще всего забыт вызов DataBind после установки DataSource. Второй вариант: запрос вернул ноль строк, а EmptyDataText не задан, поэтому таблица просто не выводится.

Нужно ли вызывать Open перед Fill?

Нет. SqlDataAdapter.Fill сам открывает закрытое соединение и закрывает его после работы. Если же вы открыли соединение вручную, Fill оставит его открытым, и закрывать придётся самостоятельно.

Где взять базу Northwind?

Скрипт instnwnd.sql публикует Microsoft в репозитории sql-server-samples на GitHub. Его достаточно выполнить в SQL Server Management Studio на любом экземпляре, включая Express и LocalDB.

Читайте также