在.NET 7和WinForms应用程序中使用SqlDependency

fafcakar  于 2023-08-07  发布在  .NET
关注(0)|答案(2)|浏览(148)

在我的Winforms应用程序中,我试图使用SqlDependency,所以我创建了这个数据访问类:

internal class DataAccessLayer 
{
    private readonly SqlConnection sqlconnection;

    public DataAccessLayer()
    {
        sqlconnection = new SqlConnection(LoginUserDetails.Connection);
    }

    // Method to open the connection
    public async Task Open()
    {
        if (sqlconnection.State != ConnectionState.Open)
        {
            await sqlconnection.OpenAsync().ConfigureAwait(false);
        }
    }

    // Method to close the connection
    public void Close()
    {
        if (sqlconnection.State == ConnectionState.Open)
        {
            sqlconnection.Close();
        }
    }

    private void AddSqlCommandParameters(SqlCommand sqlcmd, string stored_procedure)
    {
        sqlcmd.CommandType = CommandType.StoredProcedure;
        sqlcmd.CommandText = stored_procedure;
        sqlcmd.Connection = sqlconnection;
    }

    // Method to read data from database
    public async Task<DataTable> SelectDataAsync(string stored_procedure, SqlParameter[] param, OnChangeEventHandler onChangeEventHandler = null)
    {
        if (string.IsNullOrEmpty(stored_procedure))
        {
            return null;
        }

        await using var sqlCommand = new SqlCommand();

        AddSqlCommandParameters(sqlCommand, stored_procedure);

        if (param != null)
        {
            sqlCommand.Parameters.AddRange(param);
        }

        if (onChangeEventHandler != null)
        {
            var sqlDependency = new SqlDependency(sqlCommand);
            sqlDependency.OnChange += onChangeEventHandler;
        }

        using DataTable dt = new();
        using SqlDataAdapter da = new(sqlCommand);

        await Task.Run(() => da.Fill(dt)).ConfigureAwait(false);

        return dt;
    }
}

字符串
而我是这样用的

internal class CLS_Welding
{
    public static async Task<DataTable> GetWeldingPaintProduction(OnChangeEventHandler onChangeEventHandler = null)
    {
        using var DAL = new DataAccessLayer();
        return await DAL.SelectDataAsync("GetWeldingPaintProduction", null, onChangeEventHandler).ConfigureAwait(false);
    }
}


在我的Winforms中,我对窗体显示的事件调用GetWeldingPaintProduction方法,如下所示

private async Task GetData()
 {
       GCBlack.DataSource = await ClsWelding.GetWeldingPaintProductionAsync(OnDependencyChange).ConfigureAwait(false);
 }

 private void OnDependencyChange(object sender, SqlNotificationEventArgs e)
 {
     // Refresh the data.
     Invoke(new MethodInvoker(async delegate
        {
            await GetData().ConfigureAwait(false);
        }));

     // Notify the user that the data has changed.
     MessageBox.Show("The Welding Paint Production data has changed.");
}


OnDependencyChange永远不会被击中。
我已经启用了Service Broker。
这是我的存储过程:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[GetWeldingPaintProduction]
AS
    SELECT 
        daiPaiPro.[id],
        [FK_idPartShip],
        proinfo.ProjectN,
        [Parts],
        [Profile],
        [Quantity],
        [Qty] - [WeldingPaintQty] AS 'Reste Qté',
        [Length],
        [Surface],
        ProShip.[Weight],
        CAST(ProShip.[Weight] * [Quantity] AS decimal(18, 2)) AS 'Poids Tot',
        [Designation],
        [Note],
        [CreationDate],
        CONCAT(daiPaiPro.[UserID], ' ', emp.LastName_Employee, ' ', emp.FirstName_Employee) AS 'Utilisateur',
        cust.Name AS 'Client',
        ShiftTime.ShiftTime,
        FK_ShiftTime,
        FK_idNextProcess,
        ProShip.Qty,
        IdDailyWeldingProduction,
        IdDailyPrefabrication,
        SupBS.Structure
    FROM 
        [dbo].[DailyWeldingPaintProduction] daiPaiPro
    INNER JOIN 
        ProjectShipping ProShip ON ProShip.id = [FK_idPartShip]
    INNER JOIN 
        ProjectInfo proinfo ON proinfo.id = ProShip.IdProject
    INNER JOIN 
        Employee emp ON ID_Employee = daiPaiPro.[UserID]
    INNER JOIN 
        Customer cust ON cust.ID = proinfo.FK_Customer
    INNER JOIN 
        ShiftTime ON ShiftTime.id = FK_ShiftTime
    LEFT JOIN 
        StructureType SupBS ON SupBS.id = FKSupBS
    ORDER BY 
        [CreationDate] DESC
GO


我尝试插入、更新和删除。在数据库中未找到队列。
我错过了什么?
我正在使用Microsoft.Data.SqlClient Version=“5.1.1”

szqfcxe2

szqfcxe21#

我要感谢你们所有人帮助我解决这个问题
我对数据库做了这个更改

ALTER AUTHORIZATION ON DATABASE::SIM TO sa;

字符串
预览所有者(MYLIFE\MBoua)具有(sysadmin和public)角色和Windows身份验证
sa)与sql身份验证具有相同的角色(sysadmin和public)。
我觉得很奇怪。身份验证类型会造成这种差异吗?
我还将连接字符串更改为

Server=(localdb)\\MSSQLLocalDB;Database=SIM;user id=sa;password=PassWord;Encrypt=False

unhi4e5o

unhi4e5o2#

SqlCommand参数

另一个堆栈溢出用户也有类似的问题,here你可以看到如何用OnDependencyChange()钩子执行一个函数。他们的解决办法是
1.命令类型为CommandType.StoredProcedure
他们在获取SQL依赖项之前放置command.CommandType = CommandType.StoredProcedure;。(看起来你已经做到了)。
1.使用SQLConnection函数,并将存储过程名称和连接作为参数。
在您的情况下,应该将await using var sqlCommand = new SqlCommand();替换为await using var sqlCommand = new SqlCommand(stored_procedure, sqlconnection);

Service Broker

您的问题还可能是因为您的数据库不支持ServiceBroker,而ServiceBroker是SqlDependency工作所必需的。您可以使用以下SQL命令检查并启用此功能:ALTER DATABASE <database_name> SET ENABLE_BROKER这里有更多关于这个的信息。

查询通知需求

代码无法工作的另一个原因是它没有权限。您可以执行what this user did,这里还有一个启用某些权限的示例。
希望这对你有帮助。

相关问题