导航

ADO.net+VB.net制作自己的大事提醒工具milestone(一)

Posted on 2005-08-11 22:10  边缘  阅读(2247)  评论(0编辑  收藏  举报
 

Milestone的界面图如下图1所示:


    图1 Milestone的用户界面

你可以在5个文本框中填写你5件最近急需办理的要事,它们的顺序和内容可以根据情况调整,最后通过修改注册表让它随系统启动一同运行。这样你就不会忘掉一些重要的事情了,怎么样?这个工具是不是既实用又有趣呢?通过该工具的编写过程,我们一起来学习一下如何使用ADO.net和VB.net吧。

ADO.net是一组. Net框架组件。我们知道通过COM Interop功能可以使用ADODB库,完成一些访问数据的任务。但对于. Net应用程序来说,ADO.net内置于.Net框架之中,就功能和速度而言,它是无可替代的。

ADO.net提供一组对象用于处理数据:Connection,Command、DataReader和DataAdapter,还有数据集DataSet,它可以说是ADO.net的灵魂。DataSet 的设计目的很明确:为了实现独立于任何数据源的数据访问。数据集可以包含一个或多个表,这些表可以来源于一个数据库,也可以来源于多个数据库。除了包含表,数据集还可以包含说明表之间关系的对象的数据结构。ADO.NET 结构请看下图2:


    图 2 ADO.NET 结构

如果只是这样地叙述概念,你可能会觉得枯燥而不知所云,我们还是边看代码边说吧。

1、建立连接的connect.vb

Imports Microsoft.VisualBasic.Compatibility

Public Class connect

    Private str1 As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source="

    Public Function cnnc(ByVal cnn1 As OleDb.OleDbConnection)

        str1 += VB6.GetPath

        str1 += "\mesdata.mdb"

        cnn1.ConnectionString = str1

        Return cnn1

  End Function

End Class

第一句的Imports语句是从引用的项目和程序集导入命名空间名称。熟知VB6.0的朋友都知道App对象可以得到当前应用的标题、版本、路径、执行文件名等信息,同时可以用于判断应用的前一个实例是否运行。但是由于App对象在VB.NET中已经不存在了,那如何获得应用的路径呢?其实,VB.net为我们保留了这一功能,它需要在工程中先引用VisualBasic.Compatibility名称空间。请在VB.net下选择“项目”菜单点击“添加引用”,在如下对话框(如图3)中选择“Microsoft Visual Basic .NET Compatibility Runtime”并点击确定。


        图3 添加
引用VisualBasic.Compatibility

并再代码中加入这个Imports语句,第5行的str1 += VB6.GetPath中的VB6.GetPath就可以获得与App.path完全相同的结果。有了它,我们的程序运行后就能知道它的绝对路径,部署起来就方便多了。

Function cnnc返回一个OleDb.OleDbConnection类的实例cnn1。OleDbConnection对象(OleDbConnection前缀OleDb说明对象使用用于 Microsoft Jet 的 OLE DB 提供程序)来指向数据库,其它ADO.net对象就可以使用通过OleDbConnection对象指向的数据库内容了。

Private str1 As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source="中的str1是做连接字符串用的,所以这里包含一个ADO.net的数据提供者:Microsoft.Jet.OLEDB.4.0,记住使用ACCESS数据库时必须注意数据提供者。由于这个工具使用ACCESS2000作为数据库,所以使用Microsoft.Jet.OLEDB.4.0。对于不同的数据库及版本应正确选择数据提供者。

Data Source子句指定数据库文件的路径与文件名称。cnn1.ConnectionString = str1这一句将str1指定给OleDbConnection对象的ConnectionString属性。至此,有了这个connect类,就为我们的程序可以在运行时正确地找到数据库文件提供了保证。

到现在我们还没有建立本工具使用的数据库呢,不着急,现在就是做这件事的时候了。打开ACCESS2000先创建一个简单的表mes,它只需要两个字段:num(这里使用文本类型,其实还可以使用数字类型)和message(使用备注类型,目的是可以显示更多内容)。添加5个记录,字段num分别用1到5填入,message可以为空。然后关闭这个表,再创建一个新表finish,用来保存已经完成的事项内容,它有三个字段分别为:num,message和dateofover。前面两个字段的类型同上表,后面的dateofover用来记录完成时的时间,用文本类型,字段大小为20既可。注意字段名称一律应采用英文小写,否则会导致后面连接时异常。最后保存数据库的名称为mesdata.mdb。

提醒大家一个小问题:频繁地访问.mdb文件会造成.mdb文件慢慢增大,应注意在在ACCESS中点击菜单中工具→选项→常规→选中“关闭时压缩”选项,这样就防止这种情况发生了。

2、更新数据库的update.vb

Imports System.Data.OleDb

Public Class update

    Private cnn1 As New OleDbConnection

    Private dap1 As New OleDbDataAdapter

    Private das1 As New DataSet

    Private connect1 As New connect

    Public Sub updatenow(ByVal n As String, ByVal m As String)

        connect1.cnnc(cnn1)

        das1.Clear()

        dap1.SelectCommand = New OleDbCommand("Select num ,message from mes", cnn1)

        dap1.UpdateCommand = New OleDbCommand("update mes SET message=?  WHERE num= ?", cnn1)

        dap1.UpdateCommand.Parameters.Add("@message", _

                    OleDbType.Char, 65536, "message")

        dap1.UpdateCommand.Parameters.Add("@num", _

                    OleDbType.Char, 5, "num")

        cnn1.Close()

        dap1.Fill(das1, "mes")

        das1.Tables("mes").PrimaryKey = New DataColumn() {das1.Tables("mes").Columns("num")}

        Dim drw1 As DataRow = das1.Tables("mes").Rows.Find(n)

        drw1(1) = m

        dap1.Update(das1, "mes")

    End Sub

End Class

前面说了连接数据库,现在该说说更新数据库。Milestone里的事项虽然重大而紧急,但终有完成或解决的时候,即便解决不了也要延期吧,所以还要可以修改,并更新后台数据库。

为使用方便,这段程序的第一句就使用imports语句引用System.Data.OleDb命名空间,否则每次使用到.NET Framework 数据提供程序的四个核心对象时都要添加它们的命名空间。

cnn1的任务是返回一个OleDbConnection对象指定我们要连接的数据库。我们创建了一个connect类的新实例:connect1,通过它调用cnnc函数返回cnn1。注意后面用cnn1.Close()关闭连接,以释放该连接,这是个良好的习惯,不要认为.Net框架有垃圾收集机制而不去这样做。创建OleDbDataAdapter的实例dap1,OleDbDataAdapter的作用主要有两个:一是类实例可以使用数据库对象的内容,如用表或查询来填充本地数据集内的表,可用Fill方法来实现;二是类实例可以用来更新数据库中的对象,只要本地数据集有变化,就可以用它们来将本地数据集的变化传递到数据库中的资源,可用Update方法来实现这种角色。本地数据集DataSet的实例das1当然也不能少了。

介绍完这段程序将要用到的对象,下面我们来进入update过程来看看。这个过程传值调用两个参数n和m。connect1.cnnc(cnn1)的作用前面已经说过了,就是确定目标数据库。das1.Clear()的目的是清空本地数据集。这样我们就可以及时反映用户对数据库所作的修改。

数据适配器OleDbDataAdapter对象有4个属性,名称为SelctCommand、UpdateCommand、InsertCommand和DeleteCommand,后面的3个属性每个都代表一个经典的ACCESS操作,即更新已有行、插入新行、删除已有行。这里我们会用到SelctCommand、UpdateCommand这两个属性。dap1.SelectCommand语句其实很简单,你一看就会知道它是从指定的数据库按指定的SQL语句选择数据库的记录。因为mesdate.mdb就只有一个表mes,mes表中只有两个字段num、message,其实我们还可以使用Select * from mes来实现。

下面的dap1.UpdateCommand语句其实也简单,就是用指定的SQL 语句或存储过程,用于更新数据源中的记录。但是请注意,这个属性的SQL语句中包含了占位符“?”,就必须给UpdateCommand添加属性,这就是两个dap1.UpdateCommand.Parameters.Add语句的作用了,格式就是这样的。这两个语句的顺序应按照UpdateCommand对象的SQL语句中对应的占位符顺序声明,这一点往往会被忽视。注意,由于窗体textbox控件如果将MultiLine 属性设置为 true,则最多可输入 32 KB 的文本,但ACCESS的备注类型的最大空间是65536个字符(按一个字符两个字节算有131072字节共128KB),所以实际上我们在窗体的文本框中写入重要事项时最大不能超过32KB,当然实际上我们的大事件往往描述起来不需要这么多字啊。

dap1.Fill语句就是用数据适配器的SelectCommand属性选取的结果集来填充本地数据集中的表。注意前面我们已经使用das1.Clear()对本地数据集进行了清空。在讲解下面的语句之前,让我们看看数据集DataSet对象模型,如图4。注意图中对象之间的关系,其中的部分下面将要用到。


    图4 DataSet对象模型

das1.Tables("mes").PrimaryKey = New DataColumn() {das1.Tables("mes").Columns("num")}这一句是为本地数据集的mes表(本地数据集中的一个DataTable对象)指定主键(注意这与ACCESS中表的主键是两码事)。通过对DataTable对象设置主键允许Update方法自动更新本地数据集,并且只更新最近一次从数据源填充DataTable对象以来被修改过的列值。注意这个数据的类型是DataColumn,也就是本地数据集das1中(所以是Tables(“mes”),因为有两张表不然你也可以用Tables(0))的DataTable对象mes的Columns集合的num项。

Dim drw1 As DataRow = das1.Tables("mes").Rows.Find(n)定义了drw1为Rows集合中DataRow对象,das1.Tables("mes").Rows.Find(n)就是找到das1中唯一表的主键“num”中值等于n的一行并将它赋予drw1。然后就可以将m的值输入drw1(1),也就是DataRow对象中的第二列“message”,因为DataTable对象中的行、列数起于0。修改了本地数据集后,就用dap1.Update(das1, "mes")语句来更新数据源中的mes表,整个更新过程就此结束。

3、添加已完成事项到历史的addfinish.vb

Imports System.Data.OleDb

Public Class addfinish

    Private cnn1 As New OleDbConnection

    Private dap1 As New OleDbDataAdapter

    Private das1 As New DataSet

    Private connect1 As New connect

    Public Sub add(ByVal n As String, ByVal m As String)

        connect1.cnnc(cnn1)

        das1.Clear()

        dap1.SelectCommand = New OleDbCommand("Select * from finish", cnn1)

        dap1.InsertCommand = New OleDbCommand("insert into  finish (num,message,dateofover)" & "VALUES(?,?,?)", cnn1)

        dap1.InsertCommand.Parameters.Add("@num", _                                                 OleDbType.Integer, 10, "num")

        dap1.InsertCommand.Parameters.Add("@message", _

OleDbType.Char, 65536, "message")

        dap1.InsertCommand.Parameters.Add("@dateofover", _

                    OleDbType.Char, 20, "dateofover")

        cnn1.Close()

        dap1.Fill(das1, "finish")

        Dim drw1 As DataRow = das1.Tables("finish").NewRow()

        das1.Tables("finish").PrimaryKey = New DataColumn() {das1.Tables("finish").Columns(0)}

        drw1(0) = das1.Tables("finish").Rows.Count + 1

        drw1(1) = n

        drw1(2) = m

        das1.Tables("finish").Rows.Add(drw1)

        dap1.Update(das1, "finish")

    End Sub

End Class

addfinish类和前面的update类很相似,但也有以下几个地方需要注意。Dim drw1 As DataRow = das1.Tables("finish").NewRow()为本地数据集的表"finish"增添一个新行的对象drw1;本地数据集的表"finish"的主键还是要设定;drw1(0) = das1.Tables("finish").Rows.Count + 1其实就是用本地数据集的表"finish"的行数加1而得,drw1(0)是为finish表新添行的第一列;最后别忘了用dap1.Update(das1, "finish")更新数据库。

现在我们回过头来看看图2和图4,你对ADO.net是否有了一个更加清晰的认识呢?