使用 VB 2005 查看数据库结构的途径






4.55/5 (15投票s)
2006年9月14日
12分钟阅读

56476

333
本文介绍了一种方便地检查数据库中所有表、视图和列的简单方法。
引言
本文介绍了一种方便地检查数据库中所有表、视图和列的简单方法。本文旨在描述一个可用于连接数据库(Oracle、SQL Server 或 MS Access)、查看该数据库的表和视图,并深入到每个表或视图以生成其包含的所有列列表的示例应用程序。此外,该应用程序还将允许用户检查与每个列关联的定义(例如,其数据类型、标题、默认值等)。
该应用程序没有特定目的,并且只有几个关键方法与之关联。尽管该应用程序不执行任何有用的任务,但它可以作为某些有用工具的基础,例如一个可以映射一个数据库表中的字段到另一个数据库表中的字段的工具,或者它可以作为允许用户创建临时查询的工具的基础。
图 1:演示应用程序正在运行
入门
要开始,请解压缩包含的项目,然后在 Visual Studio 2005 环境中打开解决方案。在解决方案资源管理器中,您应该会注意到三个重要文件:
- AppVars.vb:包含模块中的一些应用程序范围变量。
- frmMain.vb:包含主应用程序和大部分代码。
- frmConnect.vb:包含用于连接到数据库的对话框。
应用程序变量
让我们先从提到的第一个项目文件 AppVars.vb 开始。在 IDE 中打开该文件进行查看。这只是一个代码模块,它不包含任何方法,只有一组在 frmConnect.vb 和 frmMain.vb 之间共享的变量。整个代码体如下:
Module AppVars
Public gCurrentDataModel As String 'current data model selected
Public gCurrentDatabaseType As String 'type of database used
Public gConnectionString As String 'full connect string
Public gInitialCatalog As String 'sql server initial catalog for
Public gProviderString As String 'provider name used for access
Public gServerName As String 'server name for live data access
Public gUserID As String 'its the user id used to connect
Public gPassword As String 'its the password value used
Public gCurrentTables() As String 'tables stored to populate lists
Public gCurrentViews() As String 'views stored to populate lists
End Module
定义的第一个变量用于存储数据模型名称。这仅是任意的,在此应用程序中没有实际用途;它仅用作标识连接类型的标签。
下一个变量用于存储数据库类型,例如 MS Access 或 SQL Server。
连接字符串变量,正如您可能猜到的,存储连接字符串。
初始目录变量仅用于 SQL Server 连接,它包含,是的,初始目录名称。
提供程序字符串包含数据提供程序的名称。
gUserID
和 gPassword
非常容易理解;在实际应用中,您可能希望加密密码值,事实上,您可能希望将所有这些项存储在应用程序中作为资源或其他格式,而不是将其放入模块文件中;但为了本示例的方便,模块就足够了。
gCurrentTables
和 gCurrentViews
是字符串数组,用于捕获与连接关联的所有表和视图。添加这些是为了将来可能需要持久化这些项,并在某些更有用的应用程序中更快地将其提供给控件。我确实填充了这些字符串数组,但在此演示应用程序中我并没有真正使用它们。
虽然此应用程序确实使用了带有这些变量的模块,但更好的方法是创建一组可序列化的类,其中包含每种数据库类型的属性,并在给定当前连接的情况下,实例化、填充和序列化正确的类类型。
连接对话框
连接对话框包含在 frmConnect.vb 中;此对话框用于捕获创建与 Oracle、SQL Server 或 MS Access 数据库的有效连接所需的变量。该对话框包含一个带有三个面板的选项卡式窗格,每个面板对应一种连接类型。每个面板都包含生成连接所需的所有控件。用户可以从此对话框测试连接,一旦用户接受对话框,连接信息将被持久化并提供给应用程序。
图 2:显示 SQL Server 选项的连接对话框
代码非常简单。如果您愿意在 IDE 中打开代码视图,您将看到代码文件如下开始:
Imports System.Collections
Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Runtime.Serialization
Public Class frmConnect
#Region "Declarations"
Private mCurrentDataModel As String
Private mCurrentDatabaseType As String
Private mConnectionString As String
Private mProviderString As String
Private mServerName As String
Private mInitialCatalog As String
Private mServerPort As String
Private mDatabaseName As String
Private mUserID As String
Private mPassword As String
#End Region
请注意,导入包括 Serialization
和 IO
;这些用于持久化连接信息。在声明区域,请注意声明了 AppVars.vb 文件中使用的变量的本地副本(不包括视图和表数组)。这些是将在该类中使用的成员变量。
对于每个“确定”按钮(支持的每种数据库类型都有一个),都将编写一个处理程序,该处理程序基本上遵循以下代码块:
Private Sub btnOracleOK_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnOracleOK.Click
mCurrentDataModel = "MyOracle"
mCurrentDatabaseType = "Oracle"
mProviderString = txtOracleProvider.Text
mPassword = txtOraclePassword.Text
mUserID = txtOracleUserID.Text
mServerName = txtOracleDBname.Text
mConnectionString = "Provider=" & mProviderString & _
";Password=" & mPassword & _
";User ID=" & mUserID & _
";Data Source=" & mServerName
'Test Connection
Dim cn As ADODB.Connection
cn = New ADODB.Connection
cn.CursorLocation = ADODB.CursorLocationEnum.adUseClient
Try
cn.Open(mConnectionString)
cn.Close()
cn = Nothing
Catch ex As Exception
MessageBox.Show(ex.Message.ToString(), _
"Application Settings Error", _
MessageBoxButtons.OK, _
MessageBoxIcon.Exclamation)
End Try
cn = Nothing
'set app setting global variables
AppVars.gCurrentDataModel = mCurrentDataModel
AppVars.gCurrentDatabaseType = mCurrentDatabaseType
AppVars.gConnectionString = mConnectionString
AppVars.gProviderString = mProviderString
AppVars.gServerName = mServerName
AppVars.gUserID = mUserID
AppVars.gPassword = mPassword
'create hashtable to hold settings
Dim ht As New Hashtable
ht.Add("CurrentDataModel", gCurrentDataModel)
ht.Add("CurrentDatabaseType", gCurrentDatabaseType)
ht.Add("ConnectionString", gConnectionString)
ht.Add("ProviderString", gProviderString)
ht.Add("ServerName", gServerName)
ht.Add("UserID", gUserID)
ht.Add("Password", gPassword)
'serialize data
SerializeAppVars(ht)
'cache view names
StoreViewNames()
Me.Dispose()
End Sub
此处理程序首先捕获对话框中的用户输入,并将本地变量设置为表单值;我没有在示例中这样做,但您应该验证所有这些输入。接下来,处理程序将尝试使用这些值创建连接对象,并尝试打开此连接以确认其有效。如果尝试失败,将通知用户;如果成功,值将添加到哈希表中,然后将哈希表序列化并持久化到应用程序路径中的一个文件中;这发生在 SerializeAppVars()
调用中。序列化发生后,视图和表名称将通过 StoreViewNames()
调用存储,最后,表单将被
调用处理。Me.Dispose
对话框的三个选项卡都有一个“确定”按钮,每个按钮的处理方式都与此方法一致。检查每个特定的处理程序以观察与该特定选项卡的变量相关的细微差别。
StoreViewNames()
子例程用于持久化捕获的值,以便在下次应用程序启动时可以恢复它们。这段代码更有趣:
Public Sub StoreViewNames()
Dim SchemaTable As DataTable
Dim arrViews() As String = Nothing
Dim arrTables() As String = Nothing
If AppVars.gConnectionString <> "" Then
'Connect to the database
Dim conn As New System.Data.OleDb.
OleDbConnection(AppVars.gConnectionString)
Try
conn.Open()
'get view names
SchemaTable = _
conn.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, _
New Object(){Nothing, Nothing, Nothing, Nothing})
Dim int As Integer
Dim incr As Integer = 0
For int = 0 To SchemaTable.Rows.Count - 1
If SchemaTable.Rows(int)!TABLE_TYPE.ToString = "TABLE"
Then
Dim strTempTableName As String = _
SchemaTable.Rows(int)!TABLE_NAME.ToString()
ReDim Preserve arrTables(incr + 1)
arrTables(incr) = strTempTableName
incr = incr + 1
End If
Next
For int = 0 To SchemaTable.Rows.Count - 1
If SchemaTable.Rows(int)!TABLE_TYPE.ToString = "VIEW"
Then
Dim strTempViewName As String =
SchemaTable.Rows(int)!TABLE_NAME.ToString()
ReDim Preserve arrViews(incr + 1)
arrViews(incr) = strTempViewName
incr = incr + 1
End If
Next
Catch ex As Exception
MessageBox.Show(ex.Message.ToString(), _
"Application Settings Error", _
MessageBoxButtons.OK, _
MessageBoxIcon.Exclamation)
Finally
conn.Close()
conn = Nothing
End Try
AppVars.gCurrentViews = arrViews
AppVars.gCurrentTables = arrTables
End If
End Sub
在这段代码中,请注意声明了一个名为“SchemaTable
”的 DataTable
;在建立 OleDbConnection
后,请注意将该表赋值给保存连接的架构表的代码;正是这个表使得检查数据库结构及其内容变得容易。在设置好架构表后,其余代码会遍历表的行,首先查找表,然后查找视图。找到的表被添加到包含表名称的字符串数组中,找到的视图被添加到包含视图名称的字符串数组中。
一旦数组设置好,子例程就会将这两个数组传递给 AppVars
的当前视图和当前表变量,然后结束。
SerializeAppVars()
子例程用于将变量持久化到应用程序路径中存储的文件中;此文件用于允许应用程序在最后一个已建立的连接已到位的情况下打开。用于序列化值的代码如下:
Private Sub SerializeAppVars(ByVal ht As Hashtable)
Dim strPath As String
strPath = Application.StartupPath & "\appset.con"
Dim fs As New FileStream(strPath, FileMode.OpenOrCreate)
Dim formatter As New BinaryFormatter
Try
formatter.Serialize(fs, ht)
fs.Close()
Catch ex As SerializationException
MessageBox.Show(ex.Message, "Application Settings " & _
"Serialization Error", _
MessageBoxButtons.OK, _
MessageBoxIcon.Exclamation)
End Try
End Sub
如您所见,这是一个非常简单的子例程。它接受在“确定”按钮事件处理程序中生成的哈希表,打开到名为“appset.con”的文件的文件流,该文件位于应用程序启动路径中,并使用二进制格式化器序列化哈希表并将其存储在文件中。
对话框的三个选项卡也都包含一个测试按钮。与“确定”按钮一样,所有三个测试按钮的功能几乎相同,因此我只在此文档中展示其中一个。请查看示例项目以了解三个处理程序之间的差异,但请注意,基本上只有连接字符串的变量和格式会因按钮而异。Oracle 测试按钮的处理程序如下所示:
Private Sub btnOracleTest_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnOracleTest.Click
mProviderString = txtOracleProvider.Text
mPassword = txtOraclePassword.Text
mUserID = txtOracleUserID.Text
mServerName = txtOracleDBname.Text
mConnectionString = "Provider=" & mProviderString & _
";Password=" & mPassword & _
";User ID=" & mUserID & _
";Data Source=" & mServerName
'Test Connection
Dim cn As ADODB.Connection
cn = New ADODB.Connection
cn.CursorLocation = ADODB.CursorLocationEnum.adUseClient
Try
cn.Open(mConnectionString)
cn.Close()
cn = Nothing
MessageBox.Show("Connection attempt successful, the " & _
"database connection information " & _
"provided has been successfully used " & _
"to connect to the database.", _
"Connection Successful", _
MessageBoxButtons.OK, _
MessageBoxIcon.Information)
Catch ex As Exception
MessageBox.Show("Connection attempt failed.", _
"Unable to Connect", _
MessageBoxButtons.OK, _
MessageBoxIcon.Error)
End Try
cn = Nothing
End Sub
奇怪的是,我使用了 ADO 连接来执行测试,您可以将其替换为 OleDbConnection
对象并执行相同的测试。代码很简单;您会注意到表单变量被收集并传递给本地变量。这些变量用于格式化连接字符串。连接字符串被打开作为测试;如果成功打开,测试通过;如果不成功,测试失败。用户将被告知任一结果。
连接对话框中的其余代码相当标准,用于执行诸如关闭表单或浏览文件等操作。请查看 IDE 中类的内容以了解其余内容;有足够的注释使其易于理解。
主窗体
主应用程序包含在 frmMain
类中。此表单用于访问连接对话框,并将数据库信息加载到表单控件中。表单结构顶部有一个菜单;此菜单包含退出应用程序、创建新连接、查看当前连接以及加载当前数据库关联的架构信息的选项。在表单的主区域,有三个分组框,一个包含一个列表框控件,用于显示当前数据库中的表,一个包含一个列表框控件,用于显示当前数据库中的视图,还有一个包含一个列表框控件,用于显示从表或视图列表框控件中选择的任何视图或表中的列。
图 3:主表单激活 SQL Server 连接
该类从以下代码开始:
Imports System.Data
Imports System.Data.OleDb
Imports System.Data.SqlClient
Imports System.Data.SqlTypes
Imports System.Collections
Imports System.Text
Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Runtime.Serialization
Public Class frmMain
#Region "Declarations"
Public SelectedTable As String
Private mConnectionString As String
Private mTableSelected As Boolean
#End Region
在导入部分,请注意数据和相关类库的添加;您可能需要打开项目引用并为项目添加任何缺失的引用,如果加载应用程序到 IDE 时不支持任何这些导入。导入后,添加了一个声明区域并声明了三个变量。这些变量随后在此类中使用。
图 4:演示项目引用
下一个值得关注的代码部分是表单加载事件处理程序,它看起来像这样:
Private Sub frmMain_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load
Dim mConnectionString As String = ""
DeserializeAppSettings()
If AppVars.gConnectionString <> "" Then
mConnectionString = AppVars.gConnectionString.ToString()
Me.Text = "Database - " & _
AppVars.gCurrentDatabaseType.ToString
Else
Exit Sub
End If
If Not Trim(mConnectionString) = Nothing Then
Try
OpenTablesOnStart(Trim(mConnectionString))
Catch ex As Exception
MessageBox.Show(ex.Message.ToString(), _
"Data Load Error", _
MessageBoxButtons.OK, _
MessageBoxIcon.Exclamation)
End Try
End If
End Sub
此事件处理程序很简单;如果存在现有连接文件,则将其打开并反序列化。表单标签会更新以显示当前数据库类型,如果连接字符串存在,则将其传递给一个名为 OpenTablesOnStart
的子例程,该子例程随后会将当前连接关联的表和视图加载到表和视图列表框控件中。
由表单加载事件处理程序调用的 OpenTablesOnStart
子例程用于填充表和视图列表框,其内容如下:
Private Sub OpenTablesOnStart(ByVal strConn As String)
Dim SchemaTable As DataTable
'Connect to the database
Dim conn As New System.Data.OleDb.OleDbConnection(strConn)
Try
conn.Open()
'Get table and view names
SchemaTable = _
conn.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, _
New Object(){Nothing, Nothing, Nothing, Nothing})
lstTables.Items.Clear()
lstViews.Items.Clear()
Dim int As Integer
For int = 0 To SchemaTable.Rows.Count - 1
If SchemaTable.Rows(int)!TABLE_TYPE.ToString = "TABLE" Then
lstTables.Items.Add(SchemaTable.Rows(int)!TABLE_NAME.ToString())
End If
Next
For int = 0 To SchemaTable.Rows.Count - 1
If SchemaTable.Rows(int)!TABLE_TYPE.ToString = "VIEW" Then
lstViews.Items.Add(SchemaTable.Rows(int)!TABLE_NAME.ToString())
End If
Next
Catch ex As Exception
MessageBox.Show(ex.Message.ToString(), "Data Load Error", _
MessageBoxButtons.OK, _
MessageBoxIcon.Exclamation)
End Try
conn.Close()
End Sub
快速扫描子例程将发现它以与 frmConnect
类中用于填充视图和表数组的子例程一致的方式运行。同样,声明了一个 DataTable
变量,并将其设置为包含目标数据库的架构。然后该表会循环两次,一次用于捕获表,一次用于捕获视图。收集到的视图和表会放入主表单上的列表框中。
包含视图和表的每个列表框都有一个处理程序,用于从该视图或表中恢复列并将列集合显示在字段列表框中。两个处理程序的操作方式基本相同;以下是一个示例,显示了表列表的处理程序:
Private Sub lstTables_SelectedIndexChanged(ByVal sender As _
System.Object, ByVal e As System.EventArgs) _
Handles lstTables.SelectedIndexChanged
mTableSelected = True
Dim tblName As String
tblName = lstTables.SelectedItem.ToString()
Dim conn As New System.Data.OleDb.OleDbConnection(mConnectionString)
Try
conn.Open()
lstFields.Items.Clear()
Dim dt_field As System.Data.DataTable = _
conn.GetOleDbSchemaTable( _
OleDb.OleDbSchemaGuid.Columns, _
New Object() {Nothing, Nothing, tblName})
For Each dr_field As DataRow In dt_field.Rows
Me.lstFields.Items.Add(dr_field("COLUMN_NAME").ToString)
Next
Catch ex As Exception
MessageBox.Show(ex.StackTrace, "Error", _
MessageBoxButtons.OK, _
MessageBoxIcon.Exclamation)
End Try
End Sub
同样,这一切都非常简单。子例程开头设置的 Boolean
值用于告知应用程序最后选择的项目是表;这将在其他地方使用。视图列表处理程序将此 Boolean
设置为 False
,表示视图处于活动状态而不是表。
接下来,子例程捕获选定的项并将表名变量设置为包含选定的文本。使用当前数据库连接字符串创建连接。打开连接,清除列表框中的任何现有内容,然后声明一个 DataTable
并将其设置为基于连接的当前数据库的架构表。设置好后,循环架构表的行,捕获每个列名并将其添加到列表中。最后,字段列表框将包含与最后选择的表相关的所有列名。视图列表处理程序执行完全相同的操作。
类中还有一些更简单的函数,但我将讨论的最后一个是用于恢复选定字段名称的属性的上下文菜单的处理程序。当用户从字段列表中选择一个项并右键单击它时,此上下文菜单将变为活动状态。上下文菜单将显示一个选项,该选项将调用一个函数,该函数用于收集有关选定字段的一些信息,例如数据类型、默认值、标题等。该处理程序如下所示:
Private Sub GetFieldInformationToolStripMenuItem_Click(ByVal sender _
As System.Object, ByVal e As System.EventArgs) _
Handles GetFieldInformationToolStripMenuItem.Click
Try
Dim cn As New OleDbConnection(mConnectionString)
Dim sSql As String
If mTableSelected = True Then
sSql = "SELECT [" & Me.lstFields.SelectedItem.ToString() & _
"] FROM [" & lstTables.SelectedItem.ToString() & "]"
Else
sSql = "SELECT [" & Me.lstFields.SelectedItem.ToString() & _
"] FROM [" & lstViews.SelectedItem.ToString() & "]"
End If
Dim da As New OleDbDataAdapter(sSql, cn)
cn.Open()
Dim ds As New DataSet
da.Fill(ds)
Dim sb As New StringBuilder
Dim tbl As DataTable = ds.Tables(0)
Dim col As New DataColumn
For Each col In tbl.Columns
sb.Append("Field Characteristics:" & _
Environment.NewLine & Environment.NewLine)
sb.Append("Data Type:" & Environment.NewLine)
sb.Append(col.DataType.ToString() & _
Environment.NewLine & Environment.NewLine)
sb.Append("Is Unique?" & Environment.NewLine)
sb.Append(col.Unique.ToString() & _
Environment.NewLine & Environment.NewLine)
sb.Append("Allow Nulls?" & Environment.NewLine)
sb.Append(col.AllowDBNull.ToString() & _
Environment.NewLine & Environment.NewLine)
sb.Append("Default:" & Environment.NewLine)
sb.Append(col.DefaultValue.ToString() & _
Environment.NewLine & Environment.NewLine)
sb.Append("Auto Incr:" & Environment.NewLine)
sb.Append(col.AutoIncrement.ToString() & _
Environment.NewLine & Environment.NewLine)
sb.Append("Caption:" & Environment.NewLine)
sb.Append(col.Caption.ToString())
MessageBox.Show(sb.ToString(), "Database Item " & _
"Specification for Column: " & _
col.ColumnName.ToString(), _
MessageBoxButtons.OK, _
MessageBoxIcon.Information)
Exit For
Next
Catch ex As Exception
MessageBox.Show(ex.StackTrace, ex.Message, _
MessageBoxButtons.OK, _
MessageBoxIcon.Exclamation)
End Try
End Sub
在子例程开始时,会根据最后选择的项目是表还是视图(还记得表和视图列表框处理程序中设置的 Boolean
值吗?),格式化一个 SELECT
语句。SQL 语句与数据库连接一起用于对该数据库执行查询;此查询从最后一个选定的表或视图中提取字段列表中选定的字段名。定义并填充数据适配器和数据集。完成这些任务后,定义一个数据表并将其设置为数据集的唯一表,声明一个空的 DataColumn
,然后使用它来迭代表列集合。当 DataColumn
设置为表列集合中的第一个(有一个列和一个表)时,会配置一个 StringBuilder
来捕获一些列属性。然后将此 StringBuilder
传递给消息框并显示给用户。第一次遍历完成后,
循环会手动退出。在 For
块中捕获并发送任何错误给用户。Catch
图 4:从上下文菜单选项显示列属性
摘要
该应用程序旨在演示一种构建能够动态查看数据库内容的应用程序的方法,并且严格基于连接到 MS Access、Oracle 或 SQL Server 数据库。这不是完成此任务的唯一方法,它只是一种方法。您可以轻松地修改该方法以使用其他连接类型,或添加新的连接类型,并且您可以修改应用程序以显示我在本演示中未涵盖的信息。我没有涵盖演示应用程序中包含的所有代码,因此我建议您查看解决方案中的每个类,以了解某些未涵盖的功能是如何实现的。