В прошлой теме мы рассмотрели, как выполнять команды с помощью метода ExecuteNonOuery()
, однако если мы хотим считывать данные, которые хранятся в таблице, то нам потребуется другой метод – ExecuteReader()
. Этот метод возвращает объект SqlDataReader, который используется для чтения данных. Так, получим все данные из таблицы Users и выведем их на консоль:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
static void Main(string[] args) { string connectionString = @"Data Source=.\SQLEXPRESS;Initial Catalog=usersdb;Integrated Security=True"; string sqlExpression = "SELECT * FROM Users"; using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); SqlCommand command = new SqlCommand(sqlExpression, connection); SqlDataReader reader = command.ExecuteReader(); if(reader.HasRows) // если есть данные { // выводим названия столбцов Console.WriteLine("{0}\t{1}\t{2}", reader.GetName(0), reader.GetName(1), reader.GetName(2)); while (reader.Read()) // построчно считываем данные { object id = reader.GetValue(0); object name = reader.GetValue(1); object age = reader.GetValue(2); Console.WriteLine("{0} \t{1} \t{2}", id, name, age); } } reader.Close(); } Console.Read(); } |
Для выборки данных из БД используется sql-выражение SELECT. В данном случае мы выбираем все столбцы всех строк таблицы. Получив при выполнении запроса объект SqlDataReader
, мы можем считать все полученные данные.
Но вначале мы проверяем, а есть ли вообще данные с помощью свойства HasRows
. Если данные есть, то выводим заголовки таблицы с помощью методов reader.GetName()
. Причем мы получаем столбцы в выборке именно в том порядке, в котором они определены в таблицы. То есть если вторым в таблицы идет столбец “Name”, то чтобы получить его столбец применяется метод GetName(1)
(так как нумерация столбцов идет с нуля).
Далее считываем сами данные. С помощью метода reader.Read()
ридер переходит к следующей строке и возвращает булевое значение, которое указывает, есть ли данные для считывания.
В цикле while (reader.Read())
в порядке следования столбов получаем данные с помощью метода GetValue()
, который возвращает данные в виде объекта типа object
. Например, столбец Id идет первым и представляет целое число, поэтому для его получения применяется метод reader.GetValue(0)
. А столбец Name идет вторым, поэтому его значения получаем с помощью reader.GetValue(1)
.
После завершения работы с SqlDataReader надо его закрыть методом Close()
. И пока один SqlDataReader не закрыт, другой объект SqlDataReader для одного и того же подключения мы использовать не сможем.
В качестве альтернативы мы могли бы обращаться к данным через название параметра:
1 2 3 4 5 6 7 |
while (reader.Read()) { object id = reader["id"]; object name = reader["name"]; object age = reader["age"]; Console.WriteLine("{0} \t{1} \t{2}", id, name, age); } |
этом случае результат будет аналогичным.
Асинхронное чтение
Для асинхронного чтения, во-первых, применяется метод ExecuteReaderAsync()
класса SqlCommand, и во-вторых, метод ReadAsync()
класса SqlDataReader:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
static void Main(string[] args) { ReadDataAsync().GetAwaiter(); Console.Read(); } private static async Task ReadDataAsync() { string connectionString = @"Data Source=.\SQLEXPRESS;Initial Catalog=usersdb;Integrated Security=True"; string sqlExpression = "SELECT * FROM Users"; using (SqlConnection connection = new SqlConnection(connectionString)) { await connection.OpenAsync(); SqlCommand command = new SqlCommand(sqlExpression, connection); SqlDataReader reader = await command.ExecuteReaderAsync(); if (reader.HasRows) { // выводим названия столбцов Console.WriteLine("{0}\t{1}\t{2}", reader.GetName(0), reader.GetName(1), reader.GetName(2)); while (await reader.ReadAsync()) { object id = reader.GetValue(0); object name = reader.GetValue(1); object age = reader.GetValue(2); Console.WriteLine("{0} \t{1} \t{2}", id, name, age); } } reader.Close(); } } |
Типизация результатов
В прошлой теме для получения результатов SqlDataReader использовался метод GetValue
, который возвращал значение определенного столбца в текущей ячейки в виде объекта типа object. Однако в ряде случаев такой способ не является оптимальным. Например, мы знаем, что в третьем столбце хранится возраст пользователя, который представляет целое число, и в программе мы хотели бы его использовать как целое число. Так как GetValue возвращает объект типа object, то, чтобы его использовать, к примеру, как число, нам надо его привести к типу int. Однако мы моем выбрать другой путь – использовать типизированные методы. Итак, изменим код программы следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
static void Main(string[] args) { string connectionString = @"Data Source=.\SQLEXPRESS;Initial Catalog=usersdb;Integrated Security=True"; string sqlExpression = "SELECT * FROM Users"; using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); SqlCommand command = new SqlCommand(sqlExpression, connection); SqlDataReader reader = command.ExecuteReader(); if(reader.HasRows) // если есть данные { // выводим названия столбцов Console.WriteLine("{0}\t{1}\t{2}", reader.GetName(0), reader.GetName(1), reader.GetName(2)); while (reader.Read()) // построчно считываем данные { int id = reader.GetInt32(0); string name = reader.GetString(1); int age = reader.GetInt32(2); Console.WriteLine("{0} \t{1} \t{2}", id, name, age); } } reader.Close(); } Console.Read(); } |
Для получения данных здесь теперь используются методы GetInt32()
и GetString()
, которые возвращают объекты типа int и string соответственно. Причем поскольку мы знаем, что в столбце id хранится число, то мы можем получить его именно с помощью метода GetInt32, но никак не GetString. И также в этот метод передается номер столбца в таблице (нумерация опять же начинается с нуля).
Для получения данных каждого примитивного типа есть свой метод:
Тип sql | Тип .NET | Метод |
bigint | Int64 | GetInt64 |
binary | Byte[] | GetBytes |
bit | Boolean | GetBoolean |
char | String и Char[] | GetString и GetChars |
datetime | DateTime | GetDateTime |
decimal | Decimal | GetDecimal |
float | Double | GetDouble |
image и long varbinary | Byte[] | GetBytes и GetStream |
int | Int32 | GetInt32 |
money | Decimal | GetDecimal |
nchar | String и Char[] | GetString и GetChars |
ntext | String и Char[] | GetString и GetChars |
numeric | Decimal | GetDecimal |
nvarchar | String и Char[] | GetString и GetChars |
real | Single (float) | GetFloat |
smalldatetime | DateTime | GetDateTime |
smallint | Intl6 | GetIntl6 |
smallmoney | Decimal | GetDecimal |
sql variant | Object | GetValue |
long varchar | String и Char[] | GetString и GetChars |
timestamp | Byte[] | GetBytes |
tinyint | Byte | GetByte |
uniqueidentifier | Guid | GetGuid |
varbinary | Byte[] | GetBytes |
varchar | String и Char[] | GetString и GetChars |