C# SqlDependency_OnChange()未触发

C# SqlDependency_OnChange()未触发,c#,winforms,sqldependency,C#,Winforms,Sqldependency,这是第一次使用SqlDependency,我希望能找到解决问题的答案 我面临的问题是SqlDependency_OnChange事件没有在没有错误的情况下触发 我已经在数据库中启用了代理 ALTER DATABASE databsename SET ENABLE_BROKER; 并将数据库所有者更改为sa ALTER AUTHORIZATION ON databsename TO sa; 这是我的创建表DDL CREATE TABLE [dbo].[user_log]( [user_

这是第一次使用SqlDependency,我希望能找到解决问题的答案

我面临的问题是SqlDependency_OnChange事件没有在没有错误的情况下触发

我已经在数据库中启用了代理

ALTER DATABASE databsename SET ENABLE_BROKER;
并将数据库所有者更改为sa

ALTER AUTHORIZATION ON databsename TO sa;
这是我的创建表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
有人能帮我解决这个问题吗?

下面是一个使用WinForm应用程序的简化版本和硬编码参数值的Sqldependency的示例。我修改了您问题中的存储过程,以删除对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();
            }
        }
    }
}
触发OnChange处理程序的T-SQL代码:

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将为您创建队列和服务。请注意,proc必须是一条语句并遵守。存储的proc必须包含一条SELECT语句而不包含其他任何语句。我希望OnChange事件会与SqlNotificationEventArgs一起激发:Info=Invalid,Source=Statement,Type=Subscribe@DanGuzman我已经删除了队列和服务,并将我的进程更改为一个select语句,但onchange事件仍然没有触发。请确保存储过程是从同时启用QUOTED_标识符和ANSI_NULL的会话创建的。如果需要更多帮助,请在问题中添加存储过程代码。细节很重要。如果我不清楚,进程不能包含IF语句、INSERT、DELETE等。存储过程主体中只允许一个select语句。哦,我在您发送时编写了代码,但事件仍然没有触发,我不知道出了什么问题@DanGuzman@RamadanAbdullah,将创建表DDL添加到您的问题中,我将尝试重现该问题。我已经编辑了上面的答案并编写了创建表DDL代码,谢谢您的帮助@DanGuzman@RamadanAbdullah,我看到proc调用标量函数,这将是SqlDependency的一个问题。如果从查询中删除这些内容,通知是否有效?正如我在前面的评论中提到的,OnChange处理程序应该立即被触发,因为SqlNotificationEventArgs的查询无效:Info=invalid,Source=Statement,Type=Subscribe。我已经从存储过程中删除了所有列,仅称为1列,我还删除了where子句以查看它是否有效,但仍然没有在@DanGuzman处触发