sqlDependency

sqlDependency提供了这样一种能力:当被监测的数据库中的数据发生变化时,SqlDependency会自动触发OnChange事件来通知应用程序,从而达到让系统自动更新数据(或缓存)的目的.

快速上手可参见园友的下列文章

http://www.cnblogs.com/xrinehart/archive/2006/07/27/461106.html .NET 2.0 SqlDependency快速上手指南
http://www.cnblogs.com/gesenkof99/archive/2008/12/19/1358584.html 采用SQLServer2005 Broker和SqlDependency类来提供数据更改通知(原创)

 

例子:

 

 代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication4
{
    public partial class Form1 : Form
    {
        static DataSet ds = new DataSet();
        static  string connStr = "Data Source = (local)\\SQLEXPRESS; Initial Catalog = northwind; Persist Security Info = True;User ID=sa;Password=6617saSA";
        // 必须有[dbo]. , 否则 dependency.OnChange 不断出现
        static string sql = "SELECT CustomerID  编号,CompanyName  ,ContactName ,ContactTitle  ,Address ,City  FROM [dbo].[Customers] ;";
        static  SqlDataAdapter sda ;
        static  BindingSource bindingsource1 ;
        public Form1()
        {
            InitializeComponent();
            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            dataGridView1.AllowUserToAddRows = false; //去掉DataGridView的最后一个空行
            bindingsource1 = new BindingSource();
            sda = new SqlDataAdapter(sql, connStr);
            sda.Fill(ds, "Customers");    
            bindingsource1.DataSource = ds;
            bindingsource1.DataMember = ds.Tables["Customers"].TableName;

            // 设置主键
            //在同一个 DataTable 上多次使用 Fill 方法。如果主键存在,则传入行会与已有的匹配行合并。如果主键不存在,则传入行会追加到 DataTable 中。
            DataColumn[] PrimaryKeyColumns = new DataColumn[1];
            PrimaryKeyColumns[0] = ds.Tables["Customers"].Columns["编号"];
            ds.Tables["Customers"].PrimaryKey = PrimaryKeyColumns;

            bindingNavigator1.BindingSource = bindingsource1;
            dataGridView1.DataSource = bindingsource1;

            //textBox_ID.DataBindings.Add("text", bs, "编号",false, DataSourceUpdateMode.OnPropertyChanged);
            //textBox_name.DataBindings.Add("text", bs, "CompanyName", false, DataSourceUpdateMode.OnPropertyChanged);
            textBox_ID.DataBindings.Add("text", bindingsource1, "编号");
            textBox_name.DataBindings.Add("text", bindingsource1, "CompanyName");

            textBox_ContactName.DataBindings.Add("text", bindingsource1, "ContactName");
            textBox_ContactTitle.DataBindings.Add("text", bindingsource1, "ContactTitle");
            textBox_Address.DataBindings.Add("text", bindingsource1, "Address");
            textBox_City.DataBindings.Add("text", bindingsource1, "City");

            SqlDependency.Start(connStr);//传入连接字符串,启动基于数据库的监听
            RegisterOnChangeEvent();
        }

        private void toolStripButton_save_Click(object sender, EventArgs e)
        {
            //该语句使修改cell内容后直接保存有效,否则需要移动到其它CELL再保存才有效
            dataGridView1.CurrentCell = null; 
            //将控制修改内容更新到DataSet基础数据,如果没有EndEdit() , ds.GetChanges() == null永远成立
            ((BindingSource)dataGridView1.DataSource).EndEdit();
            if (ds.GetChanges() != null)
            {
                //没有下一条会出现错误:当传递具有新行的 DataRow 集合时,Update 要求有效的 InsertCommand
                SqlCommandBuilder sb1 = new SqlCommandBuilder(sda);
                try
                {
                    sda.Update(ds.Tables["Customers"]);//更新数据库
                    ds.AcceptChanges();
                }
                catch(Exception ee)
                {
                    MessageBox.Show(ee.Message);
                } 
            }
        }

        private void RegisterOnChangeEvent()
        {          
            using (SqlConnection connection = new SqlConnection(connStr))
            {
                //依赖是基于某一张表的,而且查询语句只能是简单查询语句,不能带top或*,同时必须指定所有者,即类似[dbo].[]
                using (SqlCommand command = new SqlCommand(sql, connection))
                {
                    command.CommandType = CommandType.Text;
                    connection.Open();
                    SqlDependency dependency = new SqlDependency(command);
                    dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);

                    // Execute the command. 必须有
                    using (SqlDataReader reader = command.ExecuteReader())
                    {
                    }

                }
            }
        }

        private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
        {
            sda.Fill(ds, "Customers");
            RegisterOnChangeEvent();
        }
    }
}

 

3.测试运行

运行该控制台程序后,会输出[Messages]表的所有数据,这时不要关闭控制台程序,直接在Sql2005的管理器里对[Messages]表的数据做些修改(比如新增/删除等),再看一下控制台,会发现自动重新输出了新的数据.


注意:如果在web应用中,因为页面必须通过浏览器请求才能激活服务端的处理,所以页面一旦处理完成并显示到浏览器后,放着不动的情况下,OnChange事件始终是得不到触发的.

最后再推荐一篇园子里高人的文章:
http://www.cnblogs.com/artech/archive/2008/08/11/1265055.html 是结合Enterprise Library的缓存应用程序块与SqlDependency的综合应用,写得很不错,强烈推荐想使用缓存的朋友看看.

posted @ 2021-05-23 12:58  清语堂  阅读(799)  评论(0编辑  收藏  举报