SqlDependency - Очистка Started_Outbound разговоров - PullRequest
0 голосов
/ 25 февраля 2019

В нашем приложении нам нужно обновлять определенные поля здания (т.е. уже занято или нет) в режиме реального времени, когда любой другой пользователь, использующий это же приложение, изменяет эти поля для конкретного здания.

Однако это необходимо только в том случае, если оба пользователя в настоящее время просматривают одно и то же здание.Здание выбирается в сетке, поэтому при изменении выбранной строки я создаю новый объект SqlDependency с правильным SqlCommand.

Метод RefreshDependency:

private void RefreshDependency()
    {
        if (//Check if a row is selected at all and if it's a valid building)
        {
            if (_dependency != null)
            {
                _dependency.OnChange -= OnDependencyChange;
            }

            using (SqlConnection connection = new SqlConnection(_connectionString))
            {
                if (connection.State == ConnectionState.Closed)
                {
                    connection.Open();
                }

                using (SqlCommand command = new SqlCommand($"SELECT [MyFields] FROM [dbo.MyTable] WHERE [BuildingID] = '{selectedBuilding.ID}'", connection))
                {
                    SqlDependency dependency = new SqlDependency(command);
                    _dependency = dependency;
                    dependency.OnChange += new OnChangeEventHandler(OnDependencyChange);

                    using (SqlDataReader reader = command.ExecuteReader())
                    {
                        reader.Read();
                    }
                }

                connection.Close();
            }
        }
    }

Событие OnDependencyChange:

private void OnDependencyChange(object sender, SqlNotificationEventArgs e)
    {
        RefreshDependency();

        //Code to update fields
    }

Поскольку событие OnChange вызывается не всегда, я удаляю событие OnChange всякий раз, когда вызывается RefreshDependency, а не внутри самого события OnChange, перед его переназначением.

Теперь проблема заключается в том, что покакод работает отлично, и приложение корректно обновляется всякий раз, когда происходит изменение в базе данных, я заметил, просматривая проблему утечки памяти, вызванную SqlDependency, что каждый раз, когда создается новая SqlDependency, он создает новый диалог в sys.conversation_endpoints.Пока все в порядке, но если пользователь долго держит свой обзор открытым и выбирает, скажем, 100 зданий в течение нескольких часов, то в sys.conversation_endpoints добавляется 100 новых бесед.Тем не менее, только те, кто получит изменение, будут когда-либо фактически установлены в положение ЗАКРЫТО, остальные останутся на STARTED_OUTBOUND в течение очень долгого срока службы.

Теперь я могу очистить ЗАКРЫТЫЕ без проблем, но я неНе думаю, что я могу сделать то же самое для STARTED_OUTBOUND, чтобы я не удалил разговоры, которые на самом деле должны быть открыты для других пользователей, верно?Поскольку все, естественно, используют одну и ту же базу данных.

Я не уверен, что это полностью проблема с моим кодом, поскольку даже если когда-либо создается только одна зависимость, если никто ничего не меняет для этого здания и для пользователяпросто закрывает приложение или обзор (вызывая SqlDependency.Stop () для вызова), и этот разговор останется в STARTED_OUTBOUND.

Я заметил, что даже если поле сильно изменилось,позже, затем база данных также закроет все связанные разговоры, независимо от того, как давно они были созданы, но, учитывая, что несколько зданий могут никогда не получить изменения, я немного беспокоюсь о том, чтобы оставить эти разговоры без контроля - я знаю ЗАКРЫТОодни считаются утечкой памяти, и для них уже реализовано исправление.

Если это специально для SqlDependency, стоит ли мне вместо этого использовать альтернативы, такие как SqlDependencyEx или SqlTableDependency?

...