在现代应用程序中,实现数据流的方式多种多样,有些方法效果不错,而有些则更为优秀。本文将探讨使用ADO.NET2.0的SqlDependency和SQL Server 2005来实现应用程序实例之间的数据流。这个简单的聊天程序将展示其用法,并测试这些新特性的潜力。
本示例使用了SQL Server 2005和ADO.NET2.0的特性,并使用Visual Studio 2005创建。
SQL Server2005引入了许多新特性,其中包括服务代理(Service Broker)和查询通知(Query Notifications)。服务代理是一个内置于SQL Server 2005的队列式、可靠的消息传递机制,提供了一个健壮的异步编程模型。本文不涵盖服务代理的详细信息,更多信息可以在MSDN找到。
查询通知允许应用程序在查询结果发生变化时收到通知,这通过不必定期查询数据库来改进性能。更多信息可以在MSDN找到。
本示例的数据库并不复杂,仅足以演示本文的特性。有两个表:Message和Person。Person存储应用程序的用户,而Message存储发送的消息。要使用SqlDependency,数据库必须支持服务代理。如果数据库未启用此选项,则需要启用它。
ALTER DATABASE Chatter SET ENABLE_BROKER
SqlNotificationRequest也可以提供相同的服务,但它需要大量的手动设置。SqlDependency为设置了管道。虽然它更简单易实现,但它显然不允许某些应用程序可能需要的自定义程度,对于这些应用程序,SqlNotificationRequest将是最佳选择。
通过SqlCommand在应用程序和数据库之间创建依赖关系。在建立此依赖关系之前,必须为此会话启动SqlDependency。
SqlDependency.Start(m_ConnectionString);
处理此命令后,SQL Server将自动在连接字符串中指定的数据库中创建一个队列和一个服务。为了创建这个队列,数据库用户必须具有SUBSCRIBE QUERY NOTIFICATIONS权限。如所见,GUID用于命名这些对象。每次运行应用程序时,都会生成一个新的GUID,并创建一个新的队列和服务。尽管文档表示这些将在应用程序退出时被移除,但发现情况并非如此。
如前所述,依赖关系是基于SqlCommand创建的。
SqlDependency dependency = new SqlDependency(cmd);
当然,对于可以包含在此命令中的内容有一些限制。命令必须使用两部分名称,并且不能使用*。它显然也不能是UPDATE或INSERT语句。
以下内容将不起作用:
SELECT * FROM Message
以下内容将起作用:
SELECT ID, Message FROM dbo.Message
如果查询不正确,将立即发送事件:
SqlNotificationEventArgs.Info = Query
SqlNotificationEventArgs.Source = Statement
SqlNotificationEventArgs.Type = Subscribe
非常模糊的解释是“该语句对于通知无效”。不幸的是,还没有找到一个好的资源来说明什么构成了有效的语句。在测试过程中,使用了被证明有效的内联SQL语句,然后使用了具有完全相同语句的存储过程,它被证明是无效的。
一旦设置好依赖关系并且应用程序正在运行,所要做的就是坐下来等待接收事件。
在这个示例应用程序中,当用户发送新消息时,它将被插入到数据库中,这将导致消息被发送到服务代理队列,并被通知服务接收,进而触发OnChange事件,由应用程序处理。
void OnChange(object sender, SqlNotificationEventArgs e)
{
SqlDependency dependency = sender as SqlDependency;
// Notices are only a one shot deal
dependency.OnChange -= OnChange;
// Fire the event
if (OnNewMessage != null)
{
OnNewMessage();
}
}
通知是一次性的,因此在接收到事件后,必须重新连接以继续接收通知。在示例应用程序中,OnChange事件被移除,并向客户端触发事件,这将重新加载消息并导致依赖关系重新建立。
public DataTable GetMessages()
{
DataTable dt = new DataTable();
try
{
// Create command
// Command must use two part names for tables
// SELECT FROM dbo.Table rather than
// SELECT FROM Table
// Query also can not use *, fields
// must be designated
SqlCommand cmd = new SqlCommand("usp_GetMessages", m_sqlConn);
cmd.CommandType = CommandType.StoredProcedure;
// Clear any existing notifications
cmd.Notification = null;
// Create the dependency for this command
SqlDependency dependency = new SqlDependency(cmd);
// Add the event handler
dependency.OnChange += new OnChangeEventHandler(OnChange);
// Open the connection if necessary
if (m_sqlConn.State == ConnectionState.Closed)
m_sqlConn.Open();
// Get the messages
dt.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection));
}
catch (Exception ex)
{
throw ex;
}
return dt;
}
会注意到,不需要保持数据库连接即可接收更改事件。
本文和示例只是对SQL Server2005和ADO.NET2.0的新特性之一的快速介绍,以及它如何在应用程序中使用。
这些特性当然非常新,信息仍然有些模糊。