strip show videos

调用方式:.net 2.0 中 SqlDependency

背景需求:对于数据中表A数据字段的变更,需要引发相应业务逻辑,插入或更新相关表或字段。在以往的方式我们多会在数据库端下文章,建立相应触发器,来完 成业务逻辑操作。不过这种方式仅适用于单纯对于数据操作的需求,可是当我们要完成更复杂的业务需求是却不太容易了(虽然sql05已经支持托管代码的使用 了)。可能你会想到我们可以轮询数据库相关表或视图,来发现数据的变化,可是这对于性能和即时性却是个不容易取舍的问题。不过在 SqlServer2005中有了新的方案,那就是查询通知。

        查询通知是在 Microsoft SQL Server 2005 中以及 ADO.NET 2.0 的System.Data.SqlClient 命名空间中引入的。查询通知建立在 Service Broker 基础结构的基础上,使应用程序可以在数据更改时收到通知。如果应用程序提供数据库中信息的缓存(例如 Web 应用程序),需要在源数据更改时接收通知,此功能特别有用。

通过三种方式可以使用 ADO.NET 实现查询通知:

低级实现由 SqlNotificationRequest 类提供,该类公开服务器端功能,使您可以对通知请求执行命令。

高级实现由 SqlDependency 类提供,该类提供源应用程序与 SQL Server 之间通知功能的高级抽象,使您可以使用相关性来检测服务器中的更改。大多数情况下,这是托管客户端应用程序通过适用于 SQL Server 的 .NET Framework 数据提供程序利用 SQL Server 通知功能的最简单、最有效的方法。

此外,使用 ASP.NET 2.0(或更高版本)构建的 Web 应用程序可以使用SqlCacheDependency 帮助器类。

        如果应用程序需要通过刷新显示或缓存来响应基础数据中的更改,查询通知非常有用。如果执行相同命令生成的结果集与最初检索到的结果集不同,则 Microsoft SQL Server 可允许 .NET Framework 应用程序向 SQL Server 发送命令和请求通知。服务器上生成的通知通过队列发送,供以后处理。

您可以为 SELECT 和 EXECUTE 语句设置通知。使用 EXECUTE 语句时,SQL Server 会为执行的命令而不是 EXECUTE 语句本身注册通知。该命令必须满足 SELECT 语句的要求和限制。当注册通知的命令包含多个语句时,数据库引擎会为批处理中的每个语句创建一个通知。

使用查询通知的应用程序有一组通用的要求。必须正确配置数据源才能支持 SQL 查询通知,并且用户必须具有正确的客户端和服务器端权限。

要使用查询通知,必须符合下列条件:

1.使用 SQL Server 2005 或 SQL Server 2008。

2.对数据库启用查询通知。

3.确保用于连接数据库的用户 ID 具有必要的权限。

4.使用 SqlCommand 对象执行有效的 SELECT 语句,包含关联的通知对象 — SqlDependency 或 SqlNotificationRequest。

5.提供所监视的数据更改时用于处理通知的代码。

下面就以一个例子来说明使用SqlDependency的整个流程

using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using System.Configuration;
using System.Windows.Forms;
namespace CaptureWeb
{
public class SQLServiceBroker
{
private string connectionStr = ConfigurationManager.ConnectionStrings["ConnectionString"].ToString();
private string sqlStr = "";
private SqlConnection connection = null;
public delegate void UIDelegate();
private UIDelegate uidel = null;
public Form form = null;
/// <summary>
///
/// </summary>
/// <param name="TableName"></param>
/// <param name="ColumnNames"></param>
public SQLServiceBroker(string TableName, List<string> ColumnNames)
{
string columns = "";
foreach (string str in ColumnNames)
{
if (columns != "")
columns = columns + ",";
columns = columns + "[" + str + "]";
}
this.sqlStr = string.Format("select {0} From [dbo].[{1}]", columns, TableName);
}
/// <summary>
///
/// </summary>
/// <param name="constr"></param>
/// <param name="TableName"></param>
/// <param name="ColumnNames"></param>
public SQLServiceBroker(string constr, string TableName, List<string> ColumnNames)
: this(TableName, ColumnNames)
{
this.connectionStr = ConfigurationManager.ConnectionStrings[constr].ToString();
}
/// <summary>
///
/// </summary>
~SQLServiceBroker()
{
StopDependency();
connection.Dispose();
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public bool EnoughPermission()
{
SqlClientPermission perm = new SqlClientPermission(System.Security.Permissions.PermissionState.Unrestricted);
try
{
perm.Demand();
return true;
}
catch (System.Exception)
{
return false;
}
}
/// <summary>
///
/// </summary>
/// <param name="uidelegate"></param>
public void InitDependency(UIDelegate uidelegate)
{
SqlDependency.Stop(connectionStr);
SqlDependency.Start(connectionStr);
if (connection == null)
connection = new SqlConnection(connectionStr);
if (!EnoughPermission())
throw new Exception("没有权限(SqlClientPermission)!");
if (uidelegate == null)
throw new Exception("回调方法未指定(UIDelegate)!");
if (connection == null)
throw new Exception("未初始化(InitDependency)!");
this.uidel = uidelegate;
}
/// <summary>
/// 传入窗体对象,以防止委托有需要访问UI层控件是引发的“从不是创建控件的线程访问它”
/// </summary>
/// <param name="form1"></param>
/// <param name="uidelegate"></param>
public void InitDependency(Form form1, UIDelegate uidelegate)
{
InitDependency(uidelegate);
this.form = form1;
}
/// <summary>
///
/// </summary>
public void StartDependency()
{
//这里很奇怪,每次都需要新的command对象
using (SqlCommand command = new SqlCommand(sqlStr, connection))
{
command.Notification = null;
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State != ConnectionState.Open)
connection.Open();
command.ExecuteNonQuery();
command.Dispose();
}
}
/// <summary>
///
/// </summary>
public void StopDependency()
{
SqlDependency.Stop(connectionStr);
if (connection != null)
connection.Close();
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
//注销监测事件
SqlDependency dependency = (SqlDependency)sender;
dependency.OnChange -= dependency_OnChange;
//放在移除事件之后又很大必要,防止ui层调用更新相同表时,进入循环出发调用
//uidel.Invoke();
//uidel();
//使用from.Invoke调用防止访问界面控件引发“从不是创建控件的线程访问它”
if (form != null)
form.Invoke(uidel);
else
uidel();
//再次启动监听
StartDependency();
}
}
}


调用方式:

SQLServiceBroker broker;
private void button1_Click(object sender, EventArgs e)
{
//需要监测的列
List<string> columns = new List<string>();
columns.Add("test1");
columns.Add("test2");
string table = "test";
broker = new SQLServiceBroker(table, columns);
//实例化毁掉函数
SQLServiceBroker.UIDelegate uidel = new SQLServiceBroker.UIDelegate(writeCon);
//初始化,及传入回调函数
broker.InitDependency(uidel);
//初始化,传入窗体对象对于需要委托中访问ui控件的情况
//broker.InitDependency(this, uidel);
//启动监听
broker.StartDependency();
MessageBox.Show("启动");
}
private void writeCon()
{
MessageBox.Show("changed");
}


代码比较简单,都有说明,这里有必要注意几点问题:

1.首先需要在SQL Server 2005上执行ALTER DATABASE <DatabaseName> SET ENABLE_BROKER;语句让相应的数据库启用监听服务,以便支持SqlDependency特性。

2.对于SqlCommand的cmdText有特殊要求,其中不能用*,不能用top,不能用函数,包括聚合函数,不能用子查询,包括where后的子查询,不能用外连接,自连接,不能用临时表,不能用变量,不能用视图,不能垮库,表名之前必须加类似dbo数据库所有者这样的前缀。

3.其中在使用当中发现SqlConnection对象应该是一直存在的,因此在此示例中升级为属性,如果将它生命在StartDependency方法体中,出现只能调用一次的情况,因为对于SqlDependency需要connection对象的存在。

4.在使用委托传入调用方法是,如果方法有访问界面UI控件的情况,需要传入窗体对象,以form.Invoke(uidel);的方式调用,否则会引发“从不是创建控件的线程访问它”异常。

5.对于回调函数中需要更新正在监听的表时防止循环调用造成死循环,请在调用委托之前先移除onchange事件dependency.OnChange -= dependency_OnChange;


实例..代码..已经上传..


SQLServiceBroker broker;
private void button1_Click(object sender, EventArgs e)
{
//需要监测的列
List&amp;lt;string&amp;gt; columns = new List&amp;lt;string&amp;gt;();
columns.Add("test1");
columns.Add("test2");
string table = "test";
broker = new SQLServiceBroker(table, columns);
//实例化毁掉函数
SQLServiceBroker.UIDelegate uidel = new SQLServiceBroker.UIDelegate(writeCon);
//初始化,及传入回调函数
broker.InitDependency(uidel);
//初始化,传入窗体对象对于需要委托中访问ui控件的情况
//broker.InitDependency(this, uidel);
//启动监听
broker.StartDependency();
//在这里重新查询TEST然后绑定数据...
}
private void writeCon()
{
MessageBox.Show("changed");
}

其实只需要改动一点点



如果按照你评论说的那么简单

其实就是下面这3句话解决

public Form2()
{
InitializeComponent();
this.contextMenuStrip1.Opening+=new CancelEventHandler(contextMenuStrip1_Opening);
}
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
{
//在这里查询数据库
this.contextMenuStrip1.Items.Add("菜单项目1");
this.contextMenuStrip1.Items.Add("菜单项目2");
this.contextMenuStrip1.Items.Add("菜单项目3");
this.contextMenuStrip1.Items.Add("菜单项目4");
this.contextMenuStrip1.Items.Add("菜单项目5");
}


喜欢阅读
  • 美女总裁贴身高手

    美女总裁贴身高手

    从山上下来的神秘少年,为寻找未婚妻而展现出神秘莫测的本领,美女总裁倒追,校花要当小蜜,这些都不是幻想,“都想当我老婆,你以为谁都有资格么?”“身材不好不要,长得不倾国倾城不要,没有才艺不要,不能忍受我三妻四妾?这更不要。”一路嬉笑怒骂,受尽羡慕嫉妒恨故事就在护花路上。。。

  • 总裁的贴身特助

    总裁的贴身特助

    一场奇葩的面试,她获得了双重身份,工作日她是朝五晚九忙到脚打后脑勺的房产部女售楼,休息日她是披荆斩棘帮上司‘擦屁股’的生活女特助。他们说好只谈交易不谈感情,可突然有一天,他却对她做了出格的事……“商总,你越线了!”“这是公平交易,你用了我的东西,我也用了你的。”

  • 呆萌娇妻惹不起

    呆萌娇妻惹不起

    她左希染是谁?专业驱三师处理各种私人问题,曾是响当当的国际大盗!可没想到在一次执行任务的时候进错房间抓错人,把华国老独子,人人闻风丧胆的宋琛易当成小三!初次见面就针锋相对,败在他手下和身下,最后竟被迫做了他名义上的情人,从此两人展开相爱相杀的道路……

  • 暴力娘亲选夫记

    暴力娘亲选夫记

    当丑女变凤凰,四国美貌第一,才能第一,指挥第一。那求亲的人如滔滔流水,生过孩子,没关系,娶大送小,很划算;暴力有虐待男人的习惯,没关系,咱都是皮糙肉厚的人,很扛打;要上战场,没关系,正是要娶回家为国打战,非常好!本文一对N?错错错,本文,一对一!女强,男强,宝宝强!

  • 甜妻蜜语:帝少的宠妻大计

    甜妻蜜语:帝少的宠妻大计

        结婚数年,老公对她不仅冷眼相待,更是带了各种女人回家。她和他注定纠缠不清。为了复仇,她只能答应他的要求,各取所需。然而,当真相揭开的时候,她该何去何从?是选择相信,还是选择离开?“池琰,你明明不相信我,为什么不放过我?”男人却是紧紧扣住她的手,无比认真回答:“因为我爱你。”

  • 都市奇门神医

    都市奇门神医

    高磊作为上门女婿,尊严丧失,活的不如狗,他以为要窝囊到底,可命里注定他不会平凡。

  • 邪涩萌妻:踹了老公带球跑

    邪涩萌妻:踹了老公带球跑

    晚上八点整,陶夭动作利落地从停靠在马路上的一辆普通的私家车上跳了下来,准时出现在了苏世刚每天下班的必经之路上。根据哥哥陶然的调查,苏世刚每天这个时候都会准时出现在这里,在路边的同一家小店里买上一包烟,然后直奔夜场。苏世刚,是燕城,有权有势的高官。而陶夭今天的任务,就是要他的命!

  • 战神爸爸驾到

    战神爸爸驾到

    千古神将,灭六神,一人救一国,却救不了自己的女儿,他抛弃一切,最后的时间,只想陪在女儿身边,让她成为最幸福的人!

  • 猜你喜欢
    热门推荐
  • 月光润色ガール百科
  • 高能软泥怪13期bgm
  • 全世界失眠歌曲的寓意
  • 如何降低管理费用
  • 稻田养鸭
  • 穿越第五空间的小说
  • 我的战争 父女
  • idc全球x86服务器
  • 钢板炉批号的识别
  • 黄昏恋一朵豌豆黄网盘
  • 广西接力出版社官网
  • 98真卢卡尔出招表
  • 青春失乐园电影3
  • 木地板吊顶怎么搭配
  • 津人口计生委20146号
  • dellbios关闭uefi
  • 部队气象集训总结
  • 厦门统一预约挂号
  • 苹果7锁屏壁纸搞怪
  • medicalexamvideo
  • All Right Reserved 知识库