SQL Server 和 ADO.NET

目标

注意:本实验室重在介绍模块中的概念,与 Microsoft 的安全性建议可能有不一致之处。

 

学完本实验室的研究工作之时,您将能够:

n         构建显示绑定数据网格的 Windows 应用程序。

n         执行在运行时通常会阻止用户界面显示的长时间运行的查询。

n         使用 SqlDependency SqlNotifications

 

注意:SQL Server 2005 实验室基于 beta 版本。进行这些实验室活动的目的旨在向您提供对 SQL Server 下一个发行版本中计划具有的功能的一个总体感觉。与所有其他软件开发项目一样,最终版本在功能和用户界面上都可能与 beta 版本有所不同。有关 SQL Server 2005 的最新详情,请访问 http://www.microsoft.com/sql/2005/

 

场景

 

本实验室将向您介绍如何使用 SQL Server 2005 ADO.NET 2.0 中的新功能。在第一个练习中,通过构建即使在为长时间运行的查询提供服务时仍然允许持续性用户活动的用户界面,您将了解到如何利用 ADO.NET 2.0 的异步功能。

 

先决条件

n         能够使用 SQL Server 进行基本的编程练习

n         具有 VB.NET C# 编程的基础知识

 

完成实验估计使用时间

45 分钟

实验室设置

任务

详细步骤

1. 登录。

1.       使用 Administrator 用户帐户登录。密码是 Pass@word1

练习 1 利用 ADO.NET 的异步功能构建 Windows 表单应用程序

场景

在本练习中,您将构建一个返回数据并将数据绑定到 DataGrid 控件上的应用程序。为了填充网格,您需要执行一个模拟长时间运行的查询的命令。为了演示在等待命令结果时如何避免对用户界面的阻止,就要用到 ADO.NET 中提供的新的异步功能。尽管使用现有的 .NET 异步设计模式也可以达到目的,但是本实验使用委派来阐述这一行为。

任务

详细步骤

1. 创建 Windows 应用程序。

1.       Windows 任务栏中,通过选择 Start | All Programs | Microsoft Visual Studio 2005 Beta 2 | Microsoft Visual Studio 2005 Beta 2 启动 Visual Studio 2005

2.       从菜单中选择 File | Open | Project/Solution

3.       创建新的 Windows 应用程序(使用 C# Visual Basic .NET)。将其名称设置为 AdoNetAsync,位置为 C:/SQL Labs/User Projects

4.       Solution Explorer 窗口中,右键单击 AdoNetDependency 项目,并从上下文菜单中选择 Add Reference。在 Add Reference 对话框中,选择 System.Data.dll 并单击 OK 添加引用。您的项目可能已经包括这一引用,但是再次添加不会引起任何麻烦。为 System.Xml.dll程序集重复执行这些步骤。

 

2. 为表单添加控件。

1.       使用 View | Toolbox 菜单项确保工具箱窗口可见。在工具箱中展开 Windows Forms 选项卡,这样才可以在此部分使用控件。

2.       Form1 中添加名为 txtSql TextBox 控件。

3.       Form1 中添加名为 grdDemo DataGridView 控件。

4.       Form1 中添加名为 btnExecute Button 控件。将 Text 属性设置为“Execute”。

5.       添加名为 lblInfo Label 控件。将标签的 AutoSize 属性设置为 False。将控件停靠在表单的底部。将 Text 属性设置为“Ready”。

6.       在表单上排放控件,使其与图 1 类似。

 

1:完成的表单

 

3. 添加 Using/Import 语句和类级别变量。

创建了表单后,即可添加所需代码以便从本地 SQL Server 检索数据并将数据绑定到网格。

1.       双击 btnExecute 加载代码编辑器。

2.       System.Data.SqlClient 命名空间添加 Using/Import 语句。在 Visual Basic 中,还需要为 System.Data 命名空间添加 Import 语句:

 

' Visual Basic

Imports System.Data

Imports System.Data.SqlClient

 

// C#

using System.Data.SqlClient;

 

3.       声明名为 cmd 的专用类级别 SqlCommand 对象。如果使用 C# 编程,则将其值设置为 null

 

' Visual Basic

Private cmd As SqlCommand

 

// C#

private SqlCommand cmd = null;

 

 

4. 在表单中添加同步数据访问代码。

警告:如果创建 try-catch-finally 代码块使用了 C# 代码扩展,则必须移除 throw 语句。使用 MessageBox 来代替 throw 语句。

 

将此代码添加到 btnExecute Click Event 过程。

1.       声明名为 cnn 本地 SqlConnection 变量,该变量已初始化为 Nothing/null

 

' Visual Basic

Dim cnn As SqlConnection = Nothing

 

// C#

SqlConnection cnn = null;

 

2.       Try/Catch 块添加到过程。在 Catch 块中,捕获名为 ex Exception 对象。

3.       将代码添加到 Try 块中,直到另有说明为止。在 Try 块中,更新 lblInfo 以显示“Connecting…”:

 

' Visual Basic

lblInfo.Text = "Connecting ..."

 

// C#

lblInfo.Text = "Connecting ...";

 

4.       创建 SqlConnection 变量 cnn,并用此处显示的连接字符串实例化该变量:

 

' Visual Basic

cnn = New SqlConnection( _

"Data Source=localhost;Integrated Security=true;" & _

"Initial Catalog=AdventureWorks")

 

// C#

cnn = new SqlConnection(

"Data Source=localhost;Integrated Security=true;" +

"Initial Catalog=AdventureWorks");

 

5.       打开连接:

 

' Visual Basic

cnn.Open()

 

// C#

cnn.Open();

 

6.       更新 lblInfo 中的文本以显示“Executing…”:

 

' Visual Basic

lblInfo.Text = "Executing ..."

 

// C#

lblInfo.Text = "Executing ...";

 

7.       创建 SqlCommand 对象 cmd 的新实例,在其构造函数中,将 CommandText 参数指定为 txtSql 文本框的 Text 属性,将连接指定为前面创建的 SqlConnection 对象:

 

' Visual Basic

cmd = New SqlCommand(txtSql.Text, cnn)

 

// C#

cmd = new SqlCommand(txtSql.Text, cnn);

 

8.       创建名为 dt 的新 DataTable 实例:

 

' Visual Basic

Dim dt As New DataTable()

 

// C#

DataTable dt = new DataTable();

 

9.       创建 SqlDataReader 并调用 SqlCommand ExecuteReader 方法来为它提供数据:

 

' Visual Basic

Dim reader As SqlDataReader = _

cmd.ExecuteReader(CommandBehavior.CloseConnection )

 

// C#

SqlDataReader reader =

cmd.ExecuteReader(CommandBehavior.CloseConnection);

 

10.    调用 DataTable Load 方法,将 SqlDataReader 对象作为参数传递,然后关闭 SqlDataReader

 

' Visual Basic

dt.Load(reader)

reader.Close()

 

// C#

dt.Load(reader);

reader.Close();

 

11.    DataGrid 控件的 DataSource 属性设置为刚才填充的 DataTable

 

' Visual Basic

Me.grdDemo.DataSource = dt

 

// C#

this.grdDemo.DataSource = dt;

 

12.    更新 lblInfo 中的文本,再次显示“Ready”:

 

' Visual Basic

lblInfo.Text = "Ready"

 

// C#

lblInfo.Text = "Ready";

 

13.    Catch 块中,显示与异常对应的消息:

 

' Visual Basic

MessageBox.Show(ex.Message)

 

// C#

MessageBox.Show(ex.Message);

 

14.    完成的过程应该如下所示:

 

' Visual Basic

Dim cnn As SqlConnection = Nothing

 

Try

lblInfo.Text = "Connecting..."

cnn = New SqlConnection( _

"Data Source=localhost;Integrated Security=true;" & _

"Initial Catalog=AdventureWorks")

cnn.Open()

 

lblInfo.Text = "Executing..."

cmd = New SqlCommand(Me.txtSql.Text, cnn)

Dim dt As New DataTable

Dim reader As SqlDataReader = _

cmd.ExecuteReader(CommandBehavior.CloseConnection)

dt.Load(reader)

reader.Close()

Me.grdDemo.DataSource = dt

lblInfo.Text = "Ready"

 

Catch ex As Exception

MessageBox.Show(ex.Message)

End Try

 

// C#

SqlConnection cnn = null;

 

Try

{

lblInfo.Text = "Connecting...";

cnn = new SqlConnection(

"Data Source=localhost;Integrated Security=true;" +

"Initial Catalog=AdventureWorks");

cnn.Open();

 

lblInfo.Text = "Executing...";

cmd = new SqlCommand(this.txtSql.Text, cnn);

DataTable dt = new DataTable();

SqlDataReader reader =

cmd.ExecuteReader(CommandBehavior.CloseConnection);

dt.Load(reader);

reader.Close();

this.grdDemo.DataSource = dt;

lblInfo.Text = "Ready";

}

catch (Exception ex)

{

MessageBox.Show(ex.Message);

}

 

15.    运行应用程序。出现表单时,将以下查询输入 SQL 文本框中:

 

WAITFOR DELAY '00:00:10'; SELECT * FROM Person.Contact

 

16.    单击 Execute 按钮。注意,查询正在执行时,表单的用户界面将没有响应能力——尝试调整表单,但所做的调整在查询完成操作后才会有效果。

 

5. 在表单中添加异步数据访问代码。

 

提示:如果 IntelliSense 没有把 Invoke 方法显示为一个选项,则单击 All 选项卡。

 

此步骤将改变应用程序的实现和流。这一版本的应用程序不再同步加载数据,而使用 ADO.NET 的异步功能,以允许表单在等待结果的时候仍然具有响应能力。至关重要的一点是:使用 Windows 应用程序的异步功能时,必须确保将数据绑定到表单线程的网格,而非后台线程。由于 Windows GUI 应用程序的工作方式所限,您不能与创建表单的线程之外的任何线程的表单、表单内容或表单属性进行交互。在此例中,您已经输入的多数代码仍然可以应用,但是您需要对代码流进行一些更改,才能与异步特性相适应。

1.       在表单的类中,创建新的 Delegate 以便将数据绑定到 DataGrid

 

' Visual Basic

Private Delegate Sub UICallback(ByVal param As Object)

 

// C#

private delegate void UICallback(object param);

 

为了让此应用程序正常工作,您需要创建两个回调过程。一个是 ExecCallback,从查询返回结果时调用。另一个是 ReBindOnUIThread,与用户界面交互时才需要;例如,将查询结果绑定到网格时。此处重要的注意事项是,对于 Windows 应用程序来说,任何用户界面的交互都必须在创建表单的线程上执行,而这会使代码复杂化。

2.       创建名为 ReBindOnUIThread、包含一个类型对象参数的 void 方法/子方法。此方法可将结果数据绑定到网格。其代码与以下代码段类似:

 

' Visual Basic

Private Sub ReBindOnUIThread(ByVal param As Object)

If TypeOf param Is DataTable Then

grdDemo.DataSource = param

cmd = Nothing

lblInfo.Text = "Ready"

Else

lblInfo.Text = "Ready (last failed: " & _

CType(param, Exception).Message & ")"

End If

End Sub

 

// C#

private void ReBindOnUIThread( object param )

{

if( param is DataTable )

{

grdDemo.DataSource=param;

cmd=null;

lblInfo.Text="Ready";

}

else

lblInfo.Text="Ready (last failed: " +

((Exception)param).Message + ")";

}

 

3.       创建具有一个 IAsyncResult 类型参数、名为 ExecCallback void 方法/子方法。此方法的代码如下所示:

 

' Visual Basic

Private Sub ExecCallback(ByVal ar As IAsyncResult)

Using reader As SqlDataReader = cmd.EndExecuteReader(ar)

Try

Dim tbl As New DataTable

tbl.Load(reader)

Me.Invoke( _

New UICallback(AddressOf ReBindOnUIThread), _

New Object() {tbl})

Catch ex As Exception

Me.Invoke( _

New UICallback(AddressOf ReBindOnUIThread), _

New Object() {ex})

End Try

End Using

End Sub

 

// C#

private void ExecCallback(IAsyncResult ar)

{

using (SqlDataReader reader = cmd.EndExecuteReader(ar))

{

try

{

DataTable tbl = new DataTable();

tbl.Load(reader);

this.Invoke(new UICallback(ReBindOnUIThread),

new Object[] { tbl });

}

catch (Exception ex)

{

this.Invoke(new UICallback(ReBindOnUIThread),

new Object[] { ex });

}

}

}

 

4.       修改按钮的单击事件中的代码,以便不调用 ExecuteReader 方法,而调用新的 BeginExecuteReader 方法。此方法使用标准的 .NET 异步回调设计模式,允许传递执行操作的委派(在此例中为 ExecCallback 过程)。移除设置标签文本属性的代码。另外还必须移除创建和填充 DataTable 的代码,然后将 DataTable 绑定到 DataGridView(即,Try 块执行阅读器之后的剩余部分)——此操作需要在回调过程中进行。完成操作后,对 BeginExecuteReader 的调用应该如下所示:

 

' Visual Basic

cmd.BeginExecuteReader( _

New AsyncCallback(AddressOf ExecCallback), Nothing, _

CommandBehavior.CloseConnection)

 

// C#

cmd.BeginExecuteReader(new AsyncCallback(ExecCallback ),

null, CommandBehavior.CloseConnection);

 

5.       修改连接字符串,添加 Asynchronous Processing=true /值对。此特性允许使用连接进行异步处理:

 

' Visual Basic

cnn = New SqlConnection( _

"Data Source=.;Integrated Security=true;" & _

"Initial Catalog=AdventureWorks;" & _

"Asynchronous Processing=true")

 

// C#

cnn = new SqlConnection(

"Data Source=.;Integrated Security=true;" +

"Initial Catalog=AdventureWorks;" +

"Asynchronous Processing=true");

 

6.       catch 块中,添加代码以便将 SqlCommand cmd 设置为 null/Nothing;如果 SqlConnection 对象不是 null/Nothing,则将其关闭:

 

' Visual Basic

cmd = Nothing

If cnn IsNot Nothing Then

cnn.Close()

End If

 

// C#

cmd = null;

if (cnn != null)

{

cnn.Close();

}

 

 

7.       对代码进行其他更改,以便修改后的过程如下所示:

 

' Visual Basic

Dim cnn As SqlConnection = Nothing

 

Try

lblInfo.Text = "Connecting..."

cnn = New SqlConnection( _

"Data Source=.;Integrated Security=true;" & _

"Initial Catalog=AdventureWorks;" & _

"Asynchronous Processing=true")

cnn.Open()

 

lblInfo.Text = "Executing..."

cmd = New SqlCommand(Me.txtSql.Text, cnn)

cmd.BeginExecuteReader(New AsyncCallback( _

AddressOf ExecCallback), Nothing, _

CommandBehavior.CloseConnection)

 

Catch ex As Exception

MessageBox.Show(ex.Message)

cmd = Nothing

If cnn IsNot Nothing Then

cnn.Close()

End If

End Try

 

// C#

SqlConnection cnn = null;

 

Try

{

lblInfo.Text = "Connecting...";

cnn = new SqlConnection(

"Data Source=.;Integrated Security=true;" +

"Initial Catalog=AdventureWorks;" +

"Asynchronous Processing=true"

);

cnn.Open();

 

lblInfo.Text = "Executing...";

cmd = new SqlCommand(this.txtSql.Text, cnn);

cmd.BeginExecuteReader(

new AsyncCallback(ExecCallback), null,

CommandBehavior.CloseConnection);

}

catch (Exception ex)

{

MessageBox.Show(ex.Message);

cmd = null;

if (cnn != null)

{

cnn.Close();

}

}

 

 

8.       保存并生成应用程序。

9.       运行应用程序。当表单出现时,将以下查询输入 Textbox 控件:

 

SELECT * FROM Person.Contact

 

10.    单击 Execute。查询返回,数据网格显示绑定的数据。

11.    现在将以下查询输入 Textbox 控件。此查询是为模拟长时间运行的操作而设计的。在服务器端执行此查询的同时,还可能发生其他查询和(或)行为:

 

WAITFOR DELAY '00:00:10'; SELECT * FROM Person.Contact

 

12.    单击 Execute。注意,在执行查询的同时,用户界面仍然具有响应能力。

 

练习 2 使用 SqlDependency 创建 Windows 应用程序

场景
本实验的目标是演示 ADO.NET 所提供的新的 SqlDependency 和 SqlNotifications 基础结构。这些特性为程序员提供了执行查询的能力和从查询返回的特定数据改变时被通知的能力。与 ASP.NET 耦合时,服务器可以缓存整个响应或部分响应,从而提供更高的性能和可伸缩性。在本练习中,您需要创建两个应用程序:
1) 一个将数据绑定到数据网格的 Windows 应用程序。
2) 一个在数据库中添加、更新和删除行的 Windows 应用程序。
第一个应用程序将在检索完数据时执行命令并注册回调。第二个应用程序将对相同的数据进行更改以便 SQL Server 2005 将会通知第一个 Windows 应用程序。

任务

详细步骤

1. 构建 Windows 用户界面。

1.       Windows 任务栏中,通过选择 Start | All Programs | Microsoft Visual Studio 2005 Beta 2 | Microsoft Visual Studio 2005 Beta 2 启动 Visual Studio 2005

2.       从菜单中选择 File | Open | Project/Solution

3.       创建新的 Windows 应用程序(使用 C# Visual Basic .NET)。将其名称设置为 AdoNetDependency,其位置为 C:/SQL Labs/User Projects

4.       Solution Explorer 窗口中,右键单击 AdoNetDependency 项目,并从上下文菜单中选择 Add Reference。在 Add Reference 对话框中,选择 System.Data.dll 并单击 OK 添加引用。您的项目可能已经包括这一引用,但是再次添加不会引起任何麻烦。为 System.Xml.dll 程序集重复执行这些步骤。

5.       Toolbox 窗口的 Windows Forms 选项卡中,为在表单设计器中打开的表单添加 Label 控件。将其 Text 属性设置为“Data Source:”。

6.       在现有标签的右边,为表单添加一个文本框,并将其 Name 属性设置为 txtConnect。将 Text 属性设置为以下文本:

 

Data Source=localhost;Integrated Security=True;Initial

Catalog=AdventureWorks

 

7.       在第一个文本框/标签对的下边,添加 Label 控件。将其 Text 属性设置为“Query:”。

8.       在第二个标签的右边,添加 Textbox 控件。将 Name 属性设置为 txtSelect 并将其 Text 属性设置为以下文本:

 

SELECT ContactID, FirstName, LastName, EmailAddress FROM

Person.Contact

 

9.       在两个文本框/标签对的下边,添加 Button 控件。将其 Name 属性设置为 btnGetData 并将其 Text 属性设置为“Get Data”。

10.    在表单中添加 DataGridView 控件。将其 Name 属性设置为 grdDemo

11.    在表单的底部添加 Label 控件。将其 AutoSize 属性设置为 False。将其 Name 属性设置为 lblStatus 并从其 Text 属性中删除文本。设置标签的 Dock 属性,让它停靠在表单的底部。使用控件的句柄给出控件高度,以足够显示状态消息。

12.    此时,表单看起来应该与图2类似。

2:完成的表单

13.    双击 btnGetData 以加载代码编辑器。

14.    在表单的代码文件的顶部,添加以下 imports/using 语句:

 

' Visual Basic

Imports System.Data

Imports System.Data.SqlClient

 

// C#

using System.Data.SqlClient;

 

15.    在表单的类中,声明名为 changeCount 的类级别整数变量,并实例化名为 ds 的类级别 DataSet 变量:

 

' Visual Basic

Private changeCount As Integer

Private ds As New DataSet

 

// C#

private int changeCount = 0;

private DataSet ds = new DataSet();

 

2. 创建 GetData 方法。

注意:不要担心 DataChanged 显示为编译错误。您将在后面的步骤中创建 DataChanged 过程。

 

1.       在表单的类中,创建名为 GetData没有参数的 private/void sub/过程。

2.       在新过程中添加 Try/Catch 块。

3.       Try 块中

a.           调用表单的 DataSet ds Clear 方法。

b.           创建名为 connection 的新的 SqlConnection 对象,并将 ConnectionString 属性设置为 txtConnect.Text

c.           创建名为 adapter SqlDataAdapter 对象,在其构造函数中,传递在上一步骤中创建的 txtSelect.Text 和连接对象。

d.           创建名为 dependency 的新 SqlDependency 对象,并在其构造函数中传递 adapter.SelectCommand

e.           指定在 SqlDependency 对象的 OnChange 事件发生时,代码调用表单类中的 DataChanged 过程。其代码如下所示:

 

' Visual Basic

AddHandler dependency.OnChanged, _

AddressOf Me.DataChanged

 

// C#

dependency.OnChanged +=

new OnChangedEventHandler(this.DataChanged);

 

f.            调用 adapter.Fill 方法,指定 DataSet ds 和表“Contact”。

g.           DataGridView 控件的 DataSource 属性设置为 DataSet ds。将 DataGridView DataMember 属性设置为数据表“Contact”。

4.       Catch 块中,使用 MessageBox.Show 方法显示异常消息。

5.       完成的过程应该如下所示:

 

' Visual Basic

Private Sub GetData()

Try

ds.Clear()

Dim connection As New SqlConnection()

connection.ConnectionString = txtConnect.Text

 

Dim adapter As New SqlDataAdapter( _

txtSelect.Text, connection)

Dim dependency As New SqlDependency( _

adapter.SelectCommand)

' Don't worry that DataChanged appears as if it were a

' compile error. You'll create the DataChanged procedure

' in a later step.

 

AddHandler dependency.OnChange, _

AddressOf Me.DataChanged

 

adapter.Fill(ds, "Contact")

grdDemo.DataSource = ds

grdDemo.DataMember = "Contact"

 

Catch ex As Exception

MessageBox.Show(ex.Message)

End Try

End Sub

 

//C#

private void GetData()

{

Try

{

ds.Clear();

SqlConnection connection = new SqlConnection();

connection.ConnectionString = txtConnect.Text;

 

SqlDataAdapter adapter = new SqlDataAdapter(

txtSelect.Text, connection);

 

SqlDependency dependency =

new SqlDependency(adapter.SelectCommand);

 

// Don't worry that DataChanged appears as if it were a

// compile error. You'll create the DataChanged

// procedure in a later step.

dependency.OnChange +=

new OnChangedEventHandler(this.DataChanged);

 

adapter.Fill(ds, "Contact");

grdDemo.DataSource = ds;

grdDemo.DataMember = "Contact";

}

catch (Exception ex)

{

MessageBox.Show(ex.Message);

}

}

 

3. 创建处理 SqlDependency 通知的回调并将数据绑定到用户界面。

 

1.       在表单的类中,创建名为 ReBindOnUIThread、没有参数的 Private/void Sub/方法。当代码接收到指示已更改数据的回调时将调用此方法。

2.       ReBindOnUIThread 过程中,调用 GetData 方法,更新表单上的 Label 控件,使该过程如下所示:

 

' Visual Basic

Private Sub ReBindOnUIThread()

GetData()

Me.lblStatus.Text = _

String.Format("{0} changes have occurred.", _

changeCount)

End Sub

 

// C#

private void ReBindOnUIThread()

{

GetData();

this.lblStatus.Text =

String.Format("{0} changes have occurred.",

changeCount);

}

 

3.       在表单的类中,创建将数据绑定到网格的新 Delegate

 

' Visual Basic

Private Delegate Sub UICallback()

 

// C#

private delegate void UICallback();

 

4.       在表单的类中,创建当示例从相关对象接收到已更改数据的通知时将调用的回调过程。此代码应该如下所示:

 

' Visual Basic

Private Sub DataChanged(ByVal sender As Object, _

ByVal e As SqlNotificationEventArgs)

 

changeCount += 1

Me.Invoke(New UICallback(AddressOf ReBindOnUIThread))

End Sub

 

// C#

private void DataChanged(Object sender,

SqlNotificationEventArgs e)

{

changeCount++;

this.Invoke(new UICallback(ReBindOnUIThread));

}

 

 

4. btnGetData 单击事件中添加代码。

 

修改 btnGetData 单击事件处理程序,添加以下代码:

 

' Visual Basic

GetData()

Me.lblStatus.Text="No changes have occurred."

changeCount = 0

Me.btnGetData.Enabled = False

Me.txtSelect.Enabled = False

Me.txtConnect.Enabled = False

 

// C#

GetData();

this.lblStatus.Text="No changes have occurred.";

changeCount = 0;

this.btnGetData.Enabled = false;

this.txtSelect.Enabled = false;

this.txtConnect.Enabled = false;

 

5. 运行应用程序。

1.       选择 File | Save All 菜单命令。

2.       运行应用程序,单击按钮并检验是否使用数据填充了网格。

练习 3 构建更改应用程序

场景
在本练习中,您将构建一个在 Contact 表中插入、更新和删除数据行的应用程序。

任务

详细步骤

1. 构建用户界面。

1.       启动 Visual Studio 2005 的新实例。

2.       创建新的 Windows 应用程序(使用 C# Visual Basic .NET)。将其名称设置为 AdoNetChangeApp

3.       Solution Explorer 窗口中,右键单击 AdoNetChangeApp 项目,并从上下文菜单中选择 Add Reference。在 Add Reference 对话框中,选择 System.Data.dll 并单击 OK 添加引用。您的项目可能已经包括这一引用,但是再次添加不会引起任何麻烦。为 System.Xml.dll 程序集重复执行这些步骤。

4.       Form1 中添加 Textbox 控件。将其 Name 属性设置为 txtConnect 并将其 Text 属性设置为以下连接字符串:

 

Server=localhost; Integrated Security=true;Initial

Catalog=AdventureWorks

 

5.       在表单中添加 Label 控件。将 Label 控件的名称设置为 lblStatus。将其 AutoSize 属性设置为 False,并将其 Text 属性设置为空字符串。设置控件的 Dock 属性,使其停靠在表单的底部。使用控件的句柄给出控件的高度,以足够显示状态消息。

6.       在表单中添加三个 Button 控件,按照下面的显示设置属性:

 

名称              文本

btnAddRow        Add Row

btnUpdateRow     Update Row

btnDeleteRow      Delete Row

完成操作后,表单应该与图3类似。

3:完成的表单

 

2. 在应用程序中添加更改代码

 

1.       F7 加载代码编辑器。

2.       在表单的类中,添加 Imports/using 语句以导入 System.Data.SqlClient 命名空间。如果使用的是 Visual Basic,还需要添加 Import 语句以导入 System.Data 命名空间。

 

' Visual Basic

Imports System.Data.SqlClient

Imports System.Data

 

// C#

using System.Data.SqlClient;

 

3.       创建名为 ExecCommand 的方法/函数,它返回整数并接受一个名为 cmdText 的字符串参数。

 

' Visual Basic

Private Function ExecCommand( _

ByVal cmdText As String) As Integer

 

End Function

 

//C#

private int ExecCommand(string cmdText)

{

}

 

4.       在该过程中,创建名为 result int/Integer 类型的局部变量,并将值 0 赋予该变量。

 

' Visual Basic

Dim result As Integer = 0

 

//C#

int result = 0;

 

5.       在该过程中,添加名为 cnn SqlConnection 变量。在 C# 中,将该变量初始化为 null

 

' Visual Basic

Dim cnn As SqlConnection

 

//C#

SqlConnection cnn = null;

 

6.       在函数中添加 Try/Catch 块。在 Catch 块中,捕获名为 ex Exception 对象。

7.       Try 块中:

a.       cnn 实例化为新的 SqlConnection 对象,并将txtConnect.Text 作为连接字符串传递给构造函数。

 

' Visual Basic

cnn = New SqlConnection(txtConnect.Text)

 

//C#

cnn = new SqlConnection(txtConnect.Text);

 

b.       创建新的 SqlCommand 对象,并给构造函数传递 cmdText(传递到该过程中的参数)和新创建的 SqlConnection 对象。

 

' Visual Basic

Dim command As New SqlCommand( _

cmdText, cnn)

 

//C#

SqlCommand command =

new SqlCommand(cmdText, cnn);

 

c.       打开连接。

 

' Visual Basic

cnn.Open()

 

//C#

cnn.Open();

 

d.       调用 SqlCommand 对象的 ExecuteNonQuery 方法,并将返回值赋予名为 result 的局部变量。

 

' Visual Basic

result = command.ExecuteNonQuery()

 

//C#

result = command.ExecuteNonQuery();

 

8.       catch 块中,使用 MessageBox.Show 显示异常消息。

 

' Visual Basic

MessageBox.Show(ex.Message)

 

//C#

MessageBox.Show(ex.Message);

 

9.       添加 Finally 块,插入进行检查的代码,以确保连接不是 null/nothing;如果确实如此,则关闭连接。

 

' Visual Basic

If cnn IsNot Nothing Then

cnn.Close()

End If

 

//C#

if (cnn != null)

{

cnn.Close();

}

 

10.   返回 result 变量作为函数的返回值。

 

' Visual Basic

Return result

 

//C#

return result;

 

11.   完成的代码应该如下所示:

 

' Visual Basic

Private Function ExecCommand( _

ByVal cmdText As String) As Integer

 

Dim cnn As SqlConnection

Dim result As Integer = 0

 

Try

cnn = New SqlConnection(txtConnect.Text)

 

Dim command As New SqlCommand( _

cmdText, cnn)

 

cnn.Open()

result = command.ExecuteNonQuery()

 

Catch ex As Exception

MessageBox.Show(ex.Message)

 

Finally

If cnn IsNot Nothing Then

cnn.Close()

End If

End Try

Return result

End Function

 

//C#

private int ExecCommand(string cmdText)

{

int result = 0;

SqlConnection cnn = null;

 

Try

{

cnn = new SqlConnection(txtConnect.Text);

 

SqlCommand command =

new SqlCommand(cmdText, cnn);

 

cnn.Open();

result = command.ExecuteNonQuery();

}

catch (Exception ex)

{

MessageBox.Show(ex.Message);

}

finally

{

if (cnn != null)

{

cnn.Close();

}

}

return result;

}

 

3. 创建按钮的单击事件。

1.       在表单的类中插入以下声明:

 

' Visual Basic

Private newID As Integer = -1

 

// C#

private int newID = -1;

 

2.       将以下代码插入到 btnAddRow 单击事件处理程序中:

 

' Visual Basic

Using cnn As New SqlConnection(txtConnect.Text)

Dim cmd As New SqlCommand()

' Make up some fake values:

Dim g As Guid = Guid.NewGuid()

cmd.CommandText = _

"INSERT INTO Person.Contact " & _

"(FirstName, LastName, NameStyle, " & _

"PasswordHash, PasswordSalt, RowGuid, ModifiedDate) " & _

"VALUES ('Ken', 'Smith', 0, 'XXXXX', 'XXXXX','" & _

g.ToString() + "', '5/16/2005'); " & _

"SELECT SCOPE_IDENTITY() AS ID"

cmd.Connection = cnn

cnn.Open()

newID = Convert.ToInt32(cmd.ExecuteScalar())

End Using

 

If newID > -1 Then

Me.lblStatus.Text = "Record Added."

Else

Me.lblStatus.Text = "No Record Added."

End If

 

// C#

using (SqlConnection cnn = new

SqlConnection(txtConnect.Text))

{

SqlCommand cmd = new SqlCommand();

// Make up some fake values:

Guid g = Guid.NewGuid();

cmd.CommandText =

"INSERT INTO Person.Contact " +

"(FirstName, LastName, NameStyle, " +

"PasswordHash, PasswordSalt, RowGuid, ModifiedDate) " +

"VALUES ('Ken', 'Smith', 0, 'XXXXX', 'XXXXX','" +

g.ToString() + "', '5/16/2005'); " +

"SELECT SCOPE_IDENTITY() AS ID";

cmd.Connection = cnn;

cnn.Open();

newID = Convert.ToInt32(cmd.ExecuteScalar());

}

 

if (newID > -1)

this.lblStatus.Text = "Record added.";

else

this.lblStatus.Text = "Record not added.";

 

3.       将以下代码插入到 btnUpdateRow 单击事件处理程序中:

 

' Visual Basic

If newID > -1 Then

If ExecCommand( _

"UPDATE Person.Contact SET FirstName = 'Peter' " & _

"WHERE ContactID = " & newID.ToString()) > 0 Then

Me.lblStatus.Text = "Record Updated."

Else

Me.lblStatus.Text = "No Record Updated."

End If

Else

MessageBox.Show( _

"Row cannot be updated before it is added.")

End If

 

// C#

if (newID > -1)

{

if (ExecCommand(

"UPDATE Person.Contact SET FirstName = 'Peter' " +

"WHERE ContactID = " + newID.ToString()) > 0)

this.lblStatus.Text = "Record Updated.";

else

this.lblStatus.Text = "No Record Updated.";

}

Else

MessageBox.Show(

"Row cannot be updated before it is added.");

 

4.       将以下代码插入到 btnDeleteRow 单击事件处理程序中:

 

' Visual Basic

If newID > -1 Then

If ExecCommand( _

"DELETE FROM Person.Contact " & _

"WHERE ContactID = " & newID.ToString()) > 0 Then

Me.lblStatus.Text = "Record Deleted."

Else

Me.lblStatus.Text = "No Record Deleted."

End If

newID = -1

Else

MessageBox.Show( _

"Row cannot be deleted before it is added.")

End If

 

// C#

if (newID > -1)

{

if (ExecCommand(

"DELETE FROM Person.Contact " +

"WHERE ContactID = " + newID.ToString()) > 0)

this.lblStatus.Text = "Record Deleted.";

else

this.lblStatus.Text = "No Record Deleted.";

newID = -1;

}

Else

MessageBox.Show(

"Row cannot be deleted before it is added.");

 


练习 4 启用通知和测试

场景
在可以实际接收查询通知前,必须在每个数据库基础上启用这一特性。

任务

详细步骤

1. 启用通知。

1.       Windows 任务栏中,选择 Start | All Programs | Microsoft SQL Server 2005 | SQL Server Management Studio

2.       Connect to Server 对话框打开时,检验并确保 SQL Server 被选择作为Server type,检验并确保 Server name 与本地机器名称相同或者将其设置为 localhost,检验并确保Windows Authentication 被选择作为身份验证方法。

3.       单击 Connect

4.       通过 File | New | Database Engine Query 打开新的查询窗口并输入以下 T-SQL

 

ALTER DATABASE AdventureWorks SET ENABLE_BROKER

 

5.       F5 执行查询。

6.       关闭 SQL Server Management Studio(即使出现提示,也不用保存任何内容)。

 

2. 测试通知应用程序。

1.       运行 AdoNetDependency 应用程序。

2.       单击 Get Data 按钮,并注意文本框是只读的,数据已被绑定到网格。

3.       运行 AdoNetChange 应用程序。单击 Add 按钮并注意 AdoNetDependency 应用程序将注册这些更改并显示新数据。滚动到网格的底部,查看 Ken Smith 的新记录。

4.       单击 Update Row 按钮并注意 AdoNetDependency 应用程序接收回调并显示更新的数据。滚动到网格的底部,查看 Ken Smith 的记录,该记录现在显示 Peter Smith

5.       Delete 按钮重复这些步骤。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值