SQLDependency_OnChange-Event срабатывает только один раз.

Я работаю с SQLDependency, чтобы уведомить меня, если есть изменения в базе данных. После запуска программы он работает отлично. Когда я делаю первое изменение, событие срабатывает. Wohoo... это здорово. Но если я сделал второе изменение, событие не срабатывает снова. Я искал всю сеть, я думаю, но ничего не нашел об этой проблеме. Только обнаруженные проблемы, когда событие OnChange запускается в цикле. Кто-нибудь может мне помочь?

Здесь немного фрагмента кода:

private void GetStates()
    {
        if (!DoesUserHavePermission())
            return;

        SqlDependency.Stop(con);
        SqlDependency.Start(con);

        using (SqlConnection cn = new SqlConnection(con))
        {
            using (SqlCommand cmd = cn.CreateCommand())
            {
                cmd.CommandType = CommandType.Text;
                cmd.CommandText = "SELECT Bla, Bla2, ..FROM dbo.[BLA3]"

                cmd.Notification = null;
                cmd.Dispose();

                SqlDependency dep = new SqlDependency(cmd);
                dep.OnChange += new OnChangeEventHandler(dep_OnChange);

                cn.Open();

                using (SqlDataReader dr = cmd.ExecuteReader())
                {
                    state.Clear(); //In this Case "state" is a List<string>
                    while (dr.Read())
                    {
                        state.Add(dr.GetString(0) + "|" + dr.GetInt32(3));
                    }
                    dr.Dispose();
                    dr.Close();
                }                    
            }
        }
    }

мое событие OnChange выглядит следующим образом:

private void dep_OnChange(object sender, SqlNotificationEventArgs e)
    {
        SqlDependency dep = sender as SqlDependency;
        dep.OnChange -= this.dep_OnChange;

        using (SqlConnection cn = new SqlConnection(con))
        {
            using (SqlCommand cmd = cn.CreateCommand())
            {
                cmd.CommandType = CommandType.Text;
                cmd.CommandText = "SELECT Bla, Bla2, ..FROM dbo.[BLA3]";

                cmd.Notification = null;

                if (e.Type == SqlNotificationType.Change)
                {
                    if (cn.State != ConnectionState.Open)
                    {
                        cn.Open();
                    }

                    using (SqlDataReader dr = cmd.ExecuteReader())
                    {
                        state.Clear(); // Clear and Refill the stringlist "state"
                        while (dr.Read())
                        {
                            state.Add(dr.GetString(0) + "|" + dr.GetInt32(3));
                        }
                    }
                }
                cn.Close();
            }
        }
        this.GetStates(); //to go ahead and wait for a new change
    }

Где проблема?

Ответы

Ответ 1

Я тоже сталкивался с этой проблемой. Вам нужно создать новый объект SqlDependency (после отмены подписки на существующий из события OnChange), а затем запустить новую команду ExecuteReader. Я получил эту идею из этого сообщения:

http://www.codeproject.com/Articles/12335/Using-SqlDependency-for-data-change-events

Это обычно имеет смысл, так как как только вы получили уведомление об изменении, вы обычно захотите повторно запросить данные.

Ответ 2

В вашем методе private void dep_OnChange(object sender, SqlNotificationEventArgs e) после того, как вы отмените подписку на событие dep_OnChange, вы должны снова вызвать private void GetStates(), чтобы снова инициализировать событие dep.OnChange.

Ответ 3

Не уверен, что это ваша проблема, но вы распоряжаетесь командой сразу после ее создания:

using (SqlCommand cmd = cn.CreateCommand()) 
{
  ...
  cmd.Dispose(); 

Он выглядит как ошибка.

Ответ 4

Посмотри, мой друг:

dep.OnChange -= this.dep_OnChange;

вы не уволили свое событие; что неверно; просто удалите эту строку;

Ответ 5

В GetStates():

SqlDependency.Stop(con); SqlDependency.Start(con);

эти строки должны выполняться только при регистрации зависимостей sql в первый раз.

Ограничьте их, когда вы вызываете метод из события OnChange.