65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 SqlDependency 进行数据更改事件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.71/5 (71投票s)

2005 年 11 月 18 日

CDDL

4分钟阅读

viewsIcon

667684

downloadIcon

18155

使用 SQL Server 2005 和 SqlDependency 保持应用程序数据最新。

引言

某些应用程序需要实例之间共享数据,例如聊天程序,或者接收持续更新,例如股票经纪应用程序。有许多方法可以实现此目的,有些好,有些更好。本示例将探讨使用 ADO.NET 2.0 的 SqlDependency 和 SQL Server 2005 来在应用程序的不同实例之间提供数据流。这个简单的聊天程序将演示用法,并测试这些新功能的潜力。

注意事项

本示例使用了 SQL Server 2005 和 ADO.NET 2.0 的功能,并且是使用 Visual Studio 2005 创建的。

SQL Server 2005

SQL Server 2005 的众多新功能包括 Service Broker 和查询通知。Service Broker 是内置于 SQL Server 2005 中的一个队列式、可靠的消息传递机制,它提供了一个强大的异步编程模型。本文档不涵盖 SSB 的详细信息,更多信息可以在 MSDN 中找到。

查询通知允许应用程序在查询结果发生更改时收到通知。这通过避免周期性查询数据库以获取更改来提高性能。更多信息可以在 MSDN 中找到。

数据库

本示例的数据库并不复杂,仅足以演示本文的功能。它有两个表:Message 和 Person。Person 存储应用程序的用户,Message 存储发送的消息。要使用 SqlDependecy,数据库必须支持 Service Broker。如果数据库创建时未启用此选项,则需要启用它。

ALTER DATABASE Chatter SET ENABLE_BROKER

SqlDependency

SqlNotificationRequest 也可以提供相同的服务,但是,它需要大量手动设置。SqlDependency 为您完成了所有连接工作。虽然它实现起来更简单,但显然不允许某些应用程序可能需要的自定义程度,在这种情况下,SqlNotificationRequest 将是最佳选择。

通过 SqlCommand 在应用程序和数据库之间创建依赖关系。在建立该依赖关系之前,必须为此会话启动 SqlDependency

SqlDependency.Start(m_ConnectionString);

处理此命令后,SQL Server 将自动在连接字符串中指定的数据库中创建队列和服务。为了创建此队列,数据库用户必须拥有 *SUBSCRIBE QUERY NOTIFICATIONS* 权限。如您所见,GUID 用于命名这些对象。每次应用程序运行时,都会生成一个新的 GUID,并创建新的队列和服务。尽管文档说明当应用程序退出时这些将删除,但我发现情况并非如此。

如前所述,依赖关系是基于 SqlCommand 创建的。

SqlDependency dependency = new SqlDependency(cmd);

当然,此命令包含的内容存在一些限制。该命令必须使用两部分名称,并且不能使用 *。它显然也不能是 UPDATEINSERT 语句。

以下将不起作用

SELECT * FROM Message

以下将起作用

SELECT ID, Message FROM dbo.Message

如果查询不正确,将立即发送一个带有以下内容的事件:

SqlNotificationEventArgs.Info = Query
SqlNotificationEventArgs.Source = Statement
SqlNotificationEventArgs.Type = Subscribe

对此的解释非常模糊,是“该语句对通知无效”。不幸的是,我一直未能找到一个好的来源来描述什么是有效语句。在测试过程中,我使用了一个内联 SQL 语句,该语句被显示为有效,然后使用相同的语句的存储过程,但被显示为无效。

更新:感谢 DylanTheDeveloper 找到了描述有效查询的资源:使用查询通知时的特殊注意事项。此外,在存储过程中使用 SET NOCOUNT ON 会使其对查询通知无效。

通知

一旦设置了依赖关系并且应用程序正在运行,您所要做的就是坐等接收事件。

在此示例应用程序中,当用户发送新消息时,它将被插入数据库,这会导致消息发送到 Service Broker Queue,并由 Notification Service 拾取,后者将触发 OnChange 事件,由应用程序处理。

void OnChange(object sender, SqlNotificationEventArgs e)
{
  SqlDependency dependency = sender as SqlDependency;

  // Notices are only a one shot deal
  // so remove the existing one so a new 
  // one can be added

  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 <field> FROM dbo.Table rather than 
    // SELECT <field> 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 Server 2005 和 ADO.NET 2.0 的一项新功能及其在应用程序中的用法进行简要介绍。

这些功能当然是非常新的,信息仍然有些零散。

除了前面提到的资源之外,Sushil Chordia 的博客还包含一些关于必要权限的良好但已过时信息:DataWorks WebLog

© . All rights reserved.