Нетривиальный
пример работы с базами данных в VB .NET
(часть 2)
Вероятно,
наибольший интерес представляет
форма frmResults (комментарии следуют
после листинга). Ключевое место в
этой форме занимает метод btnQuery_Click,
выделенный жирным шрифтом:
' frmResults.vb
Imports System.Data.SqlClient
Public Class
frmResults
Inherits System.Windows.Forms.Form fRegion "Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'Вызов необходим для работы дизайнера форм Windows
InitializeComponent()
' Дальнейшая инициализация выполняется
' после вызова InitializeComponent()
End Sub
' Форма переопределяет Dispose для очистки списка компонентов.
Public Overrides Sub Dispose()
MyBase.Dispose()
If Not (components Is Nothing) Then components.
Dispose()
End If
End Sub
Private WithEvents txtQuery As System.Windows.Forms.TextBox
Private WithEvents btnQuery As System.Windows.Forms.Button
Private WithEvents IstData As System.Windows.Forms.ListBox
' Необходимо для работы дизайнера форм Windows
Private components As System.ComponentModel.Container
' ВНИМАНИЕ: следующий фрагмент необходим для дизайнера форм Windows
' Для его модификации следует использовать дизайнер форм.
' Не изменяйте его в редакторе!
<System.Diagnostics.DebuggerStepThrough()>
Private Sub _
Initial izeComponent()
Me.btnQuery = New System.Windows.Forms.Button()
Me.txtQuery = New System.Windows.Forms.TextBox()
Me.IstData = New System.Windows.Forms.ListBox()
Me.SuspendLayout()
'btnQuery
Me. btnQuery. Font = NewSystem. Orawing. Font ("Microsoft Sans Serif"._
8.5!.System.Drawing.FontStyle.Regular,
System.Drawing.GraphicsUnit.Point,CType(0.
Byte))
Me.btnQuery.Location
= New System.Drawing.Point(440. 0)
Me.btnQuery.Name =
"btnQuery"
Me.btnQuery.Size =
New System.Drawing.Size(56. 24)
Me.btnQuery.Tablndex
= 2
Me.btnQuery.Text =
"&Execute"
'txtQuery
Me. txtQuery. Font=New
System. Drawing. Font ("Microsoft Sans Serif", _
8.5!. System.Drawing.FontStyle.Regular.
System.Drawi ng.Graphi csUnit.Point.CTypet 0. Byte))
Me.txtQuery.Location = New System.Drawing.Point(8. 0)
Me.txtQuery.Name = "txtQuery"
Me.txtQuery.Size = New System.Drawing.Size(432, 20)
Me.txtQuery.Tablndex = 1
Me.txtQuery.Text =
"TextBox1"
'IstData
Me.lstData.ColumnWidth
= 120
Me.IstData.Location
= New System.Drawing.Point(8. 32)
Me.lstData.MultiColumn
= True
Me.lstData.Name =
"IstData"
Me.lstData.Size =
New System.Drawing.Size(488. 355)
Me.lstData.Tablndex
= 3
'frmResults
Me.AutoScaleBaseSize
= New System.Drawing.Size(5. 13)
Me.ClientSize = New
System.Drawing.Size(504. 397)
Me.Controls.AddRange(New
System.Windows.Forms.Control()
{Me.lstOata. Me.btnQuery, Me.txtQuery})
Me.Name = "frmResults"
Me.Text = "Query Window"
Me.ResumeLayout(False)
End Sub
#End Region
Private Sub btnQuery_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles btnQuery.Click
Try
dbCmd.CommandText =
txtQuery.Text
dbReader=dbCmd.
ExecuteReader (CoimandBehavior. Singl eResult)
' Получить
схему таблицы
Dim dtbllnfo As
DataTable = dbReader.GetSchemaTable()
' Служебная
переменная для перебора записей
Dim rwRow As DataRow
Dim strHeaders As
System.Text.StringBuilder - _
New System.Text.StringBuilder()
Dim strData As
System.Text.StringBuilder = New _
System.Text.StringBuilder()
Dim typTypesCdtbllnfo.Columns.Count) As Type
Dim intCounter As Integer = 0
' Перебрать все записи метаданных
For Each rwRow In dtblInfo.Rows
'
Определить тип
typTypes(intCounter)= rwRow("DataType") intCounter +=1
' Включить в строку имя поля
strHeaders.Append("<"
& rwRow(0) & ">" & vbTab) Next
' Занести в список заголовочную строку
1stData.Items.Add(strHeaders.ToString())
' Перебор записей данных
Do While dbReader.Read()
' Перебор
полей записи
For intCounter = 0 To (dbReader.FieldCount - 1)
' Включить содержимое поле в выходную строку
strData.Append(GetProperType(dbReader,intCounter,_
typTypes(intCounter))
& vbTab) Next
' Включить строку в список
1stData.Items.Add(strData.ToString())
' Очистить объект StringBuilder strData = New System.Text.StringBuilder()
Loop Catch except As
Exception
MsgBoxt"Error:" & except.Message)
End Try
End Sub
' Функция получает данные конкретного столбца.
Private Function
GetProperType(ByVal dr As SqlDataReader.
ByVal intPos As Integer, ByVal typType As Type) As Object
' Проверить тип поля, затем получить значение Select
Case typType.Name
Case "String"
' Преобразовать и вернуть
Return CType(dr.GetString(intPos).String)
Case "Int32"
' Преобразовать и вернуть
Return
CType(dr.Get!nt32(intPos). Int32)
' Здесь следовало бы организовать проверку всех
' остальных типов и возврат соответствующих значений.
' Мы выбрали простой путь и ограничились проверкой
' двух самых распространенных типов
Case Else
Return "<Unsupported Type>"
End Select
End Function
End Class
'При нажатии кнопки в объект команды SQL
'заносится
текст, введенный пользователем в
текстовом поле:
dbCmd.CommandText =
txtQuery.Text
(в настоящем
примере пропущена проверка данных,
необходимая в любой реальной
программе).
Далее
объявляются объекты, используемые
при чтении и выводе имен полей и их
значений:
Dim dtbllnfo As
DataTable = dbReader.GetSchemaTable()
Dim rwRow As DataRow
Dim strHeaders As
System.Text.StringBuilder = New _
System.Text.StringBuilder()
Dim strData As
System.Text.StringBuilder = New _
System.Text.Stri ngBui1der()
Dim typTypes(dtblInfo.Columns.Count)
As Type
Поскольку в
этом приложении структура базы
данных не известна заранее, мы
получаем ее описание при помощи
метода GetSchemaTable(). Этот метод
возвращает объект DataTable с
метаданными (описаниями полей
записей полученного набора).
Метаданные содержат информацию о
количестве полей в записи, их
именах и типах. На основании этой
информации можно запросить и
вывести данные из любой доступной
базы данных. Помните, что в режиме
Option Strict On (который всегда должен
быть активным) для вызова
правильной функции GetXXX() объекта
DataReader необходимо знать тип поля. По
соображениям эффективности в
приведенном примере использованы
две переменные типа Stri ngBui I der (см.
ниже). Информация, необходимая для
вывода данных в списке, извлекается
в цикле:
Dim intCounter As
Integer =0 For Each rwRow In dtbllnfo.Rows
typTypes(intCounter)
= rwRow("'DataType")
intCounter += 1
strHeaders.Append("<"
& rwRow(0) & ">" & vbTab) Next
Записи DataTable
перебираются в цикле For Each. Типы
полей сохраняются в массиве typTypes и
затем присоединяются к объекту
StringBuilder для последующего вывода
всех имен столбцов за одну операцию
(однократное обновление свойства
выполняется быстрее многократных).
Также обратите внимание на
использование имени поля в вызове
rwRow( "DataType") — структура
таблицы может измениться, что
приведет к изменению номера поля
DataType. После завершения цикла у нас
появится вся необходимая
информация об именах и типах всех
полей, и мы сможем перейти к ее
выводу в конструкции с вложенным
циклом:
Do While dbReader.Read()
For intCounter = 0
To (dbReader.FieldCount = 1)
strData.Append(GetProperType(dbReader.intCounter,
typTypes(intCounter))
& vbTab) Next
1stData.Items.Add(strData.ToString()) strData = New
System.Text.StrlngBuilder()
Loop
Первая часть
цикла напоминает аналогичные
конструкции из предыдущих примеров
— мы перебираем все поля записи,
определяем тип каждого поля и
выводим данные в списке перед
следующим вызовом Read. Для упрощения
этой задачи была написана
вспомогательная функция GetProperType().
На рис. 11.4
показан результат выборки данных
из базы Northwind.
Рис. 11.4. Результат
обработки запроса к базе данных
Northwind
В этой главе мы
постарались дать представление о
работе с ADO .NET, однако читатель
должен помнить, что перед ним лишь
предельно краткий обзор. В
частности, мы совершенно не
коснулись таких тем, как обновление
данных в хранимых процедурах,
элементы, связанные с данными, или
объекты DataAdapter/DataSet. За
подробностями обращайтесь к
специализированной литературе.