Member 11467752 Ответов: 2

Событие SqlDependency OnChange срабатывает много раз для каждого отдельного события в базе данных


Я разрабатываю систему оповещения, используя экземпляр sqldependency и SignalR, проблема я не могу заниматься, когда я изменить значение атрибута "IsOnline" в ДБ значение true или false в зависимости от статуса участника, onChange события пожары много раз, первый раз, когда новый пользователь войти я получаю два уведомления, то второй раз я становлюсь все больше похож на 4 потом еще потом еще. Количество уведомлений увеличивается каждый раз, когда новый вход или выход из системы. Я уверен, что проблема в SqlDependency, а не в SignalR, я собираюсь поделиться с вами частью своего кода.


[System.Web.Services.WebMethod]

    public static IEnumerable<AttendeeList> GetAllUsers()
    {
        var AttendeeList = new List<AttendeeList>();

        try
        {
            using (var connection = new SqlConnection(_connString))
            {
                connection.Open();
                string str = "";
                str += "SELECT [AttendeeID], ";
                str += "       [IsAllowToUploadDocuments],";
                str += "       [IsOnline], ";
                str += "       [AttendeeTypeName],";
                str += "       [UserName] ";
                str += "       FROM [dbo].[Meeting_Attendees]   ";
                str += "       INNER JOIN [dbo].[aspnet_Users]  ON [aspnet_Users].[UserId] = [Meeting_Attendees].[AttendeeID] ";
                str += "       INNER JOIN   [dbo].[AttendeeType] ON [dbo].[AttendeeType].[AttendeeTypeID] = [dbo].[Meeting_Attendees].[AttendeeTypeID] ";
                str += "       WHERE [MeetingID]=@MeetingID ORDER BY [IsOnline] DESC";

                using (var command = new SqlCommand(@str, connection))
                {
                    SqlParameter prm = new SqlParameter("@MeetingID", SqlDbType.Int);
                    prm.Direction = ParameterDirection.Input;
                    prm.DbType = DbType.Int32;
                    prm.Value = Convert.ToInt32(Properties.Settings.Default.MeetingID);
                    command.Parameters.Add(prm);
                    command.Notification = null;

                    var dependency = new SqlDependency(command);
                    dependency.OnChange += new OnChangeEventHandler(dependencyUsers_OnChange);

                    if (connection.State == ConnectionState.Closed)
                        connection.Open();

                    var reader = command.ExecuteReader();

                    while (reader.Read())
                    {
                        AttendeeList.Add(item: new AttendeeList { UserName = (string)reader["UserName"], UserType = (string)reader["AttendeeTypeName"], IsOnline = (bool)reader["IsOnline"], IsAllowToUploadDocuments = (bool)reader["IsAllowToUploadDocuments"], IsCurrentUser = true ? (Guid)reader["AttendeeID"] == new Guid(Properties.Settings.Default.UserID.ToString()) : false });
                    }
                }
            }
        }
        catch { }
        return AttendeeList;
    }

    private static void dependencyUsers_OnChange(object sender, SqlNotificationEventArgs e)
    {
        if (e.Type == SqlNotificationType.Change && e.Info == SqlNotificationInfo.Update)
        {
            //Call SignalR
            MessagesHub.UpdateUsers();
        }
    }

2 Ответов

Рейтинг:
2

Arsenije Arsenijevic

Я знаю, что вопрос старый, но вижу, что на него нет ответа, просто ссылаются на рабочий пример.

Вы создаете новое SqlDependency объектов на каждый вызов GetAllUsers метод (который, как я предполагаю, не вызывается только один раз) и не останавливает старые. Это приводит к многократному SqlDependency объекты следят за идентичными изменениями в базе данных, и каждый раз, когда вы вызываете GetAllUsers метод вы добавляете еще один, и это умножается в забвении.
Более правильным способом сделать это было бы иметь отдельный метод для инициализации SqlDependency объект(Ы) и вызов его только один раз.

Надеюсь, я вам помог.
Овации.


Рейтинг:
2

Wendelius

Во-первых, уведомление может произойти даже в том случае, если фактических изменений в данных нет. Это может произойти, например, если сервер находится под большой нагрузкой или даже проблемы с уведомлением могут спровоцировать событие. Вы можете попробовать использовать HasChanges[^] если это показывает ситуацию по-другому.

Одна вещь, которая может повысить точность, - это удаление параметра и использование вместо него литерала.

Что касается увеличения количества уведомлений каждый раз, то это звучит так, как будто вы каждый раз создаете новые подписки, не прекращая старые. Возможно, каждый вызов веб-метода создает новый прослушиватель. Howebver, из кода я не могу найти вызовы для запуска или остановки методов... Например, взгляните на пример в разделе Обнаружение изменений с помощью SqlDependency[^].