SqlDependency_OnChange() 没有开火
SqlDependency_OnChange() not firing
第一次使用SqlDependency,希望能找到问题的答案
我面临的问题是 SqlDependency_OnChange 事件没有正确触发
我在数据库中启用了代理
ALTER DATABASE databsename SET ENABLE_BROKER;
并将数据库所有者更改为 sa
ALTER AUTHORIZATION ON databsename TO sa;
这是我创建的 Table DDL
CREATE TABLE [dbo].[user_log](
[user_log_id] [bigint] NOT NULL,
[user_name] [nvarchar](100) NULL,
[action_type_id] [int] NULL,
[document_type_id] [int] NULL,
[document_id] [nvarchar](20) NULL,
[description] [nvarchar](200) NULL,
[action_date] [datetime] NULL,
[seen] [bit] NULL,
CONSTRAINT [PK_user_log] PRIMARY KEY CLUSTERED
(
[user_log_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
并在 visual studio
中编写了这段代码
public User_Actions_Log_Form()
{
InitializeComponent();
try
{
SqlClientPermission SCP = new SqlClientPermission(System.Security.Permissions.PermissionState.Unrestricted);
SCP.Demand();
}
catch (Exception)
{
throw;
}
DA.DataAccess DAL = new DA.DataAccess();
SqlDependency.Stop(DAL.MyConnectionString().ConnectionString);
SqlDependency.Start(DAL.MyConnectionString().ConnectionString);
}
DataTable dt = new DataTable();
public void SearchUserLog()
{
BL.UserLogBL usr_log_bl = new BL.UserLogBL();
usr_log_bl.UserName = CBUser.SelectedValue == null ? null : CBUser.SelectedValue.ToString();
usr_log_bl.ActionTypeID = CBActionType.SelectedValue == null ? null : CBActionType.SelectedValue.ToString();
usr_log_bl.DocumentTypeID = CBDocumentType.SelectedValue == null ? null : CBDocumentType.SelectedValue.ToString();
usr_log_bl.DateFrom = DTPFrom.Checked? DTPFrom.Value.Date:(DateTime?)null;
usr_log_bl.DateTo = DTPTo.Checked ? DTPTo.Value.Date.AddSeconds(86340) : (DateTime?)null;
DA.DataAccess DAL = new DA.DataAccess();
using (SqlConnection con = new SqlConnection(DAL.MyConnectionString().ConnectionString))
{
SqlCommand cmd = new SqlCommand();
if (con.State == ConnectionState.Closed)
{
con.Open();
}
cmd.Connection = con;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "dbo.ManageUserLog";
SqlParameter[] para = new SqlParameter[7];
para[0] = new SqlParameter("@check", "s");
para[1] = new SqlParameter("@user_name", usr_log_bl.UserName);
para[2] = new SqlParameter("@action_type_id", usr_log_bl.ActionTypeID);
para[3] = new SqlParameter("@document_type_id", usr_log_bl.DocumentTypeID);
para[4] = new SqlParameter("@date_from", usr_log_bl.DateFrom);
para[5] = new SqlParameter("@date_to", usr_log_bl.DateTo);
para[6] = new SqlParameter("@seen", usr_log_bl.Seen);
cmd.Parameters.AddRange(para);
var depenedency = new SqlDependency(cmd);
cmd.Notification = null;
depenedency.OnChange += new OnChangeEventHandler(sqlDependency_OnChange);
dt.Rows.Clear();
dt.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection));
dataGridView1.DataSource = dt;
}
}
private void sqlDependency_OnChange(object sender, SqlNotificationEventArgs e)
{
SqlDependency SD = sender as SqlDependency;
SD.OnChange -= sqlDependency_OnChange;
if (OnNewUserActionsLogForm != null)
{
User_Actions_Log_Form_OnNewHome();
}
}
public delegate void New_User_Actions_Log_Form();
public event New_User_Actions_Log_Form OnNewUserActionsLogForm;
private void User_Actions_Log_Form_Load(object sender, EventArgs e)
{
OnNewUserActionsLogForm += new New_User_Actions_Log_Form(User_Actions_Log_Form_OnNewHome);
SearchUserLog();
}
private void User_Actions_Log_Form_OnNewHome()
{
ISynchronizeInvoke i = (ISynchronizeInvoke)this;
if (i.InvokeRequired)
{
New_User_Actions_Log_Form dd = new New_User_Actions_Log_Form(User_Actions_Log_Form_OnNewHome);
i.BeginInvoke(dd, null);
return;
}
SearchUserLog();
}
这是我调用的 sql 过程
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER proc [dbo].[ManageUserLog]
(
@user_name nvarchar(100) = null,
@action_type_id int = null,
@document_type_id int = null,
@date_from datetime = null,
@date_to datetime = null,
@seen bit = null
)
as
begin
select user_log_id,
[user_name],
dbo.GetActionTypeByID(action_type_id) as action_type,
dbo.GetDocumentTypeByID(document_type_id) as document_type,
document_id,
[description],
action_date,
seen
from dbo.user_log
where (@user_name is null or [user_name] = @user_name)
and (@action_type_id is null or action_type_id = @action_type_id)
and (@document_type_id is null or document_type_id = @document_type_id)
and (action_date between @date_from and @date_to)
and (seen = @seen)
end
谁能帮我解决这个问题
下面是一个 Minimal, Complete, and Verifiable example 的工作 Sqldependency,它使用带有硬编码参数值的简化版本的 WinForm 应用程序。我修改了您问题中的存储过程以删除函数调用(对 SqlDependency 通知无效)并从 C# 代码中删除了 @check
SqlCommand 参数,因为该参数未在存储过程中定义。
此示例适用于我的系统,因此我希望它会在数据更改时触发您的开发箱上的 OnChange 处理程序。
T-SQL设置码:
CREATE DATABASE YourDatabase;
GO
ALTER DATABASE YourDatabase SET ENABLE_BROKER;
GO
USE YourDatabase;
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[user_log](
[user_log_id] [bigint] NOT NULL,
[user_name] [nvarchar](100) NULL,
[action_type_id] [int] NULL,
[document_type_id] [int] NULL,
[document_id] [nvarchar](20) NULL,
[description] [nvarchar](200) NULL,
[action_date] [datetime] NULL,
[seen] [bit] NULL,
CONSTRAINT [PK_user_log] PRIMARY KEY CLUSTERED
(
[user_log_id] ASC
)
);
GO
INSERT INTO dbo.user_log(user_log_id, user_name, action_date, seen)
VALUES(1,'test', '2018-04-15T00:00:00', 1);
GO
CREATE proc [dbo].[ManageUserLog]
(
@user_name nvarchar(100) = null,
@action_type_id int = null,
@document_type_id int = null,
@date_from datetime = null,
@date_to datetime = null,
@seen bit = null
)
as
begin
select user_log_id,
[user_name],
--dbo.GetActionTypeByID(action_type_id) as action_type,
--dbo.GetDocumentTypeByID(document_type_id) as document_type,
document_id,
[description],
action_date,
seen
from dbo.user_log
where (@user_name is null or [user_name] = @user_name)
and (@action_type_id is null or action_type_id = @action_type_id)
and (@document_type_id is null or document_type_id = @document_type_id)
and (action_date between @date_from and @date_to)
and (seen = @seen)
end
GO
GRANT EXEC ON dbo.ManageUserLog TO public;
GO
C# WinForm 代码:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
static string connectionString = @"Data Source=.;Initial Catalog=YourDatabase;Integrated Security=SSPI";
public Form1()
{
InitializeComponent();
SqlDependency.Start(connectionString);
SearchUserLog();
}
public void SearchUserLog()
{
DataTable dt = new DataTable();
using (SqlConnection con = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand())
{
con.Open();
cmd.Connection = con;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "dbo.ManageUserLog";
SqlParameter[] para = new SqlParameter[6];
para[0] = new SqlParameter("@user_name", "test");
para[1] = new SqlParameter("@action_type_id", System.DBNull.Value);
para[2] = new SqlParameter("@document_type_id", System.DBNull.Value);
para[3] = new SqlParameter("@date_from", DateTime.Parse("2018-04-15"));
para[4] = new SqlParameter("@date_to", DateTime.Parse("2018-04-16"));
para[5] = new SqlParameter("@seen", 1);
cmd.Parameters.AddRange(para);
var depenedency = new SqlDependency(cmd);
depenedency.OnChange += new OnChangeEventHandler(sqlDependency_OnChange);
dt.Rows.Clear();
dt.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection));
}
}
private void sqlDependency_OnChange(object sender, SqlNotificationEventArgs e)
{
MessageBox.Show($"OnChange Event fired. SqlNotificationEventArgs: Info={e.Info}, Source={e.Source}, Type={e.Type}\r\n");
//resubscribe only if valid
if ((e.Info != SqlNotificationInfo.Invalid)
&& (e.Type != SqlNotificationType.Subscribe))
{
SearchUserLog();
}
}
}
}
T-SQL 触发 OnChange 处理程序的代码:
DECLARE @ID int = (SELECT MAX(user_log_id)+1 FROM dbo.user_log);
INSERT INTO dbo.user_log(user_log_id, user_name, action_date, seen)
VALUES(@ID,'test', '2018-04-15T00:00:00', 1);
GO
第一次使用SqlDependency,希望能找到问题的答案
我面临的问题是 SqlDependency_OnChange 事件没有正确触发
我在数据库中启用了代理
ALTER DATABASE databsename SET ENABLE_BROKER;
并将数据库所有者更改为 sa
ALTER AUTHORIZATION ON databsename TO sa;
这是我创建的 Table DDL
CREATE TABLE [dbo].[user_log](
[user_log_id] [bigint] NOT NULL,
[user_name] [nvarchar](100) NULL,
[action_type_id] [int] NULL,
[document_type_id] [int] NULL,
[document_id] [nvarchar](20) NULL,
[description] [nvarchar](200) NULL,
[action_date] [datetime] NULL,
[seen] [bit] NULL,
CONSTRAINT [PK_user_log] PRIMARY KEY CLUSTERED
(
[user_log_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
并在 visual studio
中编写了这段代码 public User_Actions_Log_Form()
{
InitializeComponent();
try
{
SqlClientPermission SCP = new SqlClientPermission(System.Security.Permissions.PermissionState.Unrestricted);
SCP.Demand();
}
catch (Exception)
{
throw;
}
DA.DataAccess DAL = new DA.DataAccess();
SqlDependency.Stop(DAL.MyConnectionString().ConnectionString);
SqlDependency.Start(DAL.MyConnectionString().ConnectionString);
}
DataTable dt = new DataTable();
public void SearchUserLog()
{
BL.UserLogBL usr_log_bl = new BL.UserLogBL();
usr_log_bl.UserName = CBUser.SelectedValue == null ? null : CBUser.SelectedValue.ToString();
usr_log_bl.ActionTypeID = CBActionType.SelectedValue == null ? null : CBActionType.SelectedValue.ToString();
usr_log_bl.DocumentTypeID = CBDocumentType.SelectedValue == null ? null : CBDocumentType.SelectedValue.ToString();
usr_log_bl.DateFrom = DTPFrom.Checked? DTPFrom.Value.Date:(DateTime?)null;
usr_log_bl.DateTo = DTPTo.Checked ? DTPTo.Value.Date.AddSeconds(86340) : (DateTime?)null;
DA.DataAccess DAL = new DA.DataAccess();
using (SqlConnection con = new SqlConnection(DAL.MyConnectionString().ConnectionString))
{
SqlCommand cmd = new SqlCommand();
if (con.State == ConnectionState.Closed)
{
con.Open();
}
cmd.Connection = con;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "dbo.ManageUserLog";
SqlParameter[] para = new SqlParameter[7];
para[0] = new SqlParameter("@check", "s");
para[1] = new SqlParameter("@user_name", usr_log_bl.UserName);
para[2] = new SqlParameter("@action_type_id", usr_log_bl.ActionTypeID);
para[3] = new SqlParameter("@document_type_id", usr_log_bl.DocumentTypeID);
para[4] = new SqlParameter("@date_from", usr_log_bl.DateFrom);
para[5] = new SqlParameter("@date_to", usr_log_bl.DateTo);
para[6] = new SqlParameter("@seen", usr_log_bl.Seen);
cmd.Parameters.AddRange(para);
var depenedency = new SqlDependency(cmd);
cmd.Notification = null;
depenedency.OnChange += new OnChangeEventHandler(sqlDependency_OnChange);
dt.Rows.Clear();
dt.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection));
dataGridView1.DataSource = dt;
}
}
private void sqlDependency_OnChange(object sender, SqlNotificationEventArgs e)
{
SqlDependency SD = sender as SqlDependency;
SD.OnChange -= sqlDependency_OnChange;
if (OnNewUserActionsLogForm != null)
{
User_Actions_Log_Form_OnNewHome();
}
}
public delegate void New_User_Actions_Log_Form();
public event New_User_Actions_Log_Form OnNewUserActionsLogForm;
private void User_Actions_Log_Form_Load(object sender, EventArgs e)
{
OnNewUserActionsLogForm += new New_User_Actions_Log_Form(User_Actions_Log_Form_OnNewHome);
SearchUserLog();
}
private void User_Actions_Log_Form_OnNewHome()
{
ISynchronizeInvoke i = (ISynchronizeInvoke)this;
if (i.InvokeRequired)
{
New_User_Actions_Log_Form dd = new New_User_Actions_Log_Form(User_Actions_Log_Form_OnNewHome);
i.BeginInvoke(dd, null);
return;
}
SearchUserLog();
}
这是我调用的 sql 过程
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER proc [dbo].[ManageUserLog]
(
@user_name nvarchar(100) = null,
@action_type_id int = null,
@document_type_id int = null,
@date_from datetime = null,
@date_to datetime = null,
@seen bit = null
)
as
begin
select user_log_id,
[user_name],
dbo.GetActionTypeByID(action_type_id) as action_type,
dbo.GetDocumentTypeByID(document_type_id) as document_type,
document_id,
[description],
action_date,
seen
from dbo.user_log
where (@user_name is null or [user_name] = @user_name)
and (@action_type_id is null or action_type_id = @action_type_id)
and (@document_type_id is null or document_type_id = @document_type_id)
and (action_date between @date_from and @date_to)
and (seen = @seen)
end
谁能帮我解决这个问题
下面是一个 Minimal, Complete, and Verifiable example 的工作 Sqldependency,它使用带有硬编码参数值的简化版本的 WinForm 应用程序。我修改了您问题中的存储过程以删除函数调用(对 SqlDependency 通知无效)并从 C# 代码中删除了 @check
SqlCommand 参数,因为该参数未在存储过程中定义。
此示例适用于我的系统,因此我希望它会在数据更改时触发您的开发箱上的 OnChange 处理程序。
T-SQL设置码:
CREATE DATABASE YourDatabase;
GO
ALTER DATABASE YourDatabase SET ENABLE_BROKER;
GO
USE YourDatabase;
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[user_log](
[user_log_id] [bigint] NOT NULL,
[user_name] [nvarchar](100) NULL,
[action_type_id] [int] NULL,
[document_type_id] [int] NULL,
[document_id] [nvarchar](20) NULL,
[description] [nvarchar](200) NULL,
[action_date] [datetime] NULL,
[seen] [bit] NULL,
CONSTRAINT [PK_user_log] PRIMARY KEY CLUSTERED
(
[user_log_id] ASC
)
);
GO
INSERT INTO dbo.user_log(user_log_id, user_name, action_date, seen)
VALUES(1,'test', '2018-04-15T00:00:00', 1);
GO
CREATE proc [dbo].[ManageUserLog]
(
@user_name nvarchar(100) = null,
@action_type_id int = null,
@document_type_id int = null,
@date_from datetime = null,
@date_to datetime = null,
@seen bit = null
)
as
begin
select user_log_id,
[user_name],
--dbo.GetActionTypeByID(action_type_id) as action_type,
--dbo.GetDocumentTypeByID(document_type_id) as document_type,
document_id,
[description],
action_date,
seen
from dbo.user_log
where (@user_name is null or [user_name] = @user_name)
and (@action_type_id is null or action_type_id = @action_type_id)
and (@document_type_id is null or document_type_id = @document_type_id)
and (action_date between @date_from and @date_to)
and (seen = @seen)
end
GO
GRANT EXEC ON dbo.ManageUserLog TO public;
GO
C# WinForm 代码:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
static string connectionString = @"Data Source=.;Initial Catalog=YourDatabase;Integrated Security=SSPI";
public Form1()
{
InitializeComponent();
SqlDependency.Start(connectionString);
SearchUserLog();
}
public void SearchUserLog()
{
DataTable dt = new DataTable();
using (SqlConnection con = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand())
{
con.Open();
cmd.Connection = con;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "dbo.ManageUserLog";
SqlParameter[] para = new SqlParameter[6];
para[0] = new SqlParameter("@user_name", "test");
para[1] = new SqlParameter("@action_type_id", System.DBNull.Value);
para[2] = new SqlParameter("@document_type_id", System.DBNull.Value);
para[3] = new SqlParameter("@date_from", DateTime.Parse("2018-04-15"));
para[4] = new SqlParameter("@date_to", DateTime.Parse("2018-04-16"));
para[5] = new SqlParameter("@seen", 1);
cmd.Parameters.AddRange(para);
var depenedency = new SqlDependency(cmd);
depenedency.OnChange += new OnChangeEventHandler(sqlDependency_OnChange);
dt.Rows.Clear();
dt.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection));
}
}
private void sqlDependency_OnChange(object sender, SqlNotificationEventArgs e)
{
MessageBox.Show($"OnChange Event fired. SqlNotificationEventArgs: Info={e.Info}, Source={e.Source}, Type={e.Type}\r\n");
//resubscribe only if valid
if ((e.Info != SqlNotificationInfo.Invalid)
&& (e.Type != SqlNotificationType.Subscribe))
{
SearchUserLog();
}
}
}
}
T-SQL 触发 OnChange 处理程序的代码:
DECLARE @ID int = (SELECT MAX(user_log_id)+1 FROM dbo.user_log);
INSERT INTO dbo.user_log(user_log_id, user_name, action_date, seen)
VALUES(@ID,'test', '2018-04-15T00:00:00', 1);
GO