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的综合应用,写得很不错,强烈推荐想使用缓存的朋友看看.