Как я могу уведомить мою программу, когда база данных была обновлена? - PullRequest
10 голосов
/ 16 сентября 2010

У меня есть программа C #, которая запрашивает базу данных SQL Server для некоторых значений.

В настоящее время приложение запрашивает базу данных каждую минуту, чтобы убедиться, что таблица обновлена.

Что я хотел бы сделать, так это то, что запрос выполняется только тогда, когда база данных была изменена / обновлена. Как я могу уведомить мою программу, когда что-то было обновлено в базе данных?

Спасибо

Ответы [ 5 ]

9 голосов
/ 16 сентября 2010

Опросная база данных - не очень элегантное решение.

SqlDependency от ADO.NET будет полезно в вашем случае.Он не использует опрос, но механизм уведомления.Уведомления предоставляются компонентом Service Broker в вашей базе данных, поэтому необходимо включить эту службу в вашей базе данных.Событие OnChange произойдет при изменении указанной таблицы (обновление, удаление, вставка ..)

Вот пример использования SqlDependency:

void Initialization()
{
    // Create a dependency connection.
    SqlDependency.Start(connectionString, queueName);
}

void SomeMethod()
{
    // Assume connection is an open SqlConnection.

    // Create a new SqlCommand object.
    using (SqlCommand command=new SqlCommand(
        "SELECT ShipperID, CompanyName, Phone FROM dbo.Shippers", 
        connection))
    {

        // Create a dependency and associate it with the SqlCommand.
        SqlDependency dependency=new SqlDependency(command);
        // Maintain the refence in a class member.

        // Subscribe to the SqlDependency event.
        dependency.OnChange+=new
           OnChangeEventHandler(OnDependencyChange);

        // Execute the command.
        using (SqlDataReader reader = command.ExecuteReader())
        {
            // Process the DataReader.
        }
    }
}

// Handler method
void OnDependencyChange(object sender, 
   SqlNotificationEventArgs e )
{
  // Handle the event (for example, invalidate this cache entry).
}

void Termination()
{
    // Release the dependency.
    SqlDependency.Stop(connectionString, queueName);
}

из http://msdn.microsoft.com/en-us/library/62xk7953.aspx

Вот как включить компонент Service Broker (обратите внимание, что для этого у вас будет эксклюзивность в базе данных - лучше всего это сделать после перезапуска сервера sql): http://blogs.sftsrc.com/stuart/archive/2007/06/13/42.aspx(Broken ссылка)

Возможна альтернативная ссылка: http://technet.microsoft.com/en-us/library/ms166086(v=sql.105).aspx

4 голосов
/ 16 сентября 2010

Если вы используете SQL Server 2005 и выше, вы можете рассмотреть возможность использования объекта SqlDependency.

Он представляет зависимость уведомления о запросе между приложением и экземпляром SQL Server 2005.

Приложение может создать объект SqlDependency и зарегистрироваться для получения уведомлений через обработчик событий OnChangeEventHandler.

См. Эту ссылку в MSDN для получения дополнительной информации

Однако обратите внимание на предостережениечто MS ставит против его использования.Рекомендуется иметь уровень кэширования, а затем использовать SQLDependency в координации с этим уровнем.

SqlDependency был разработан для использования в ASP.NET или службах среднего уровня, где имеется относительно небольшое количествосерверы, имеющие зависимости от базы данных.Он не предназначен для использования в клиентских приложениях, где сотни или тысячи клиентских компьютеров будут иметь объекты SqlDependency, настроенные для одного сервера базы данных.

3 голосов
/ 26 ноября 2015

Чтобы получить уведомление при обновлении какой-либо записи, избегайте приложения для запроса таблицы, которую вы используете TableDependency компонент (в вашем конкретном случае SqlTableDependency ). Вот пример:

public partial class Window1 : Window
{
    private IList<Stock> _stocks;
    private readonly string _connectionString = 
        "data source=.;initial catalog=myDB;integrated security=True";
    private readonly SqlTableDependency<Stock> _dependency;

    public Window1()
    {
        this.InitializeComponent();
        this.McDataGrid.ItemsSource = LoadCollectionData();
        this.Closing += Window1_Closing;

        var mapper = new ModelToTableMapper<Stock>();
        mapper.AddMapping(model => model.Symbol, "Code");

        _dependency = new SqlTableDependency<Stock>(_connectionString, "Stocks", mapper);
        _dependency.OnChanged += _dependency_OnChanged;
        _dependency.OnError += _dependency_OnError;
        _dependency.Start();
    }

    private void Window1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
    {
        _dependency.Stop();
    }

    private void _dependency_OnError(object sender, TableDependency.EventArgs.ErrorEventArgs e)
    {
        throw e.Error;
    }

    private void _dependency_OnChanged(
        object sender, 
        TableDependency.EventArgs.RecordChangedEventArgs<Stock> e)
    {
        if (_stocks != null)
        {
            if (e.ChangeType != ChangeType.None)
            {
                switch (e.ChangeType)
                {
                    case ChangeType.Delete:
                        _stocks.Remove(_stocks.FirstOrDefault(c => c.Symbol == e.Entity.Symbol));
                        break;
                    case ChangeType.Insert:
                        _stocks.Add(e.Entity);
                        break;
                    case ChangeType.Update:
                        var customerIndex = _stocks.IndexOf(
                                _stocks.FirstOrDefault(c => c.Symbol == e.Entity.Symbol));
                        if (customerIndex >= 0) _stocks[customerIndex] = e.Entity;
                        break;
                }

                this.McDataGrid.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() =>
                {
                    this.McDataGrid.Items.Refresh();
                }));
            }
        }
    }

    private IEnumerable<Stock> LoadCollectionData()
    {
        _stocks = new List<Stock>();

        using (var sqlConnection = new SqlConnection(_connectionString))
        {
            sqlConnection.Open();
            using (var sqlCommand = sqlConnection.CreateCommand())
            {
                sqlCommand.CommandText = "SELECT * FROM [Stocks]";

                using (var sqlDataReader = sqlCommand.ExecuteReader())
                {
                    while (sqlDataReader.Read())
                    {
                        var code = sqlDataReader
                                .GetString(sqlDataReader.GetOrdinal("Code"));
                        var name = sqlDataReader
                                .GetString(sqlDataReader.GetOrdinal("Name"));
                        var price = sqlDataReader
                                .GetDecimal(sqlDataReader.GetOrdinal("Price"));

                        _stocks.Add(new Stock { Symbol = code, Name = name, Price = price });
                    }
                }
            }
        }

        return _stocks;
    }

Обработчик событий запускается для каждой операции INSERT UPDATE или DELETE, выполняемой в таблице, сообщая вам об измененном значении. Поэтому, если вы заинтересованы в обновлении данных C #, вы просто можете получить свежие данные из обработчика событий.

2 голосов
/ 16 сентября 2010

Что я хотел бы сделать, так это то, что запрос выполняется только тогда, когда база данных была изменена / обновлена. Как я могу уведомить мою программу, когда что-то будет обновлено в базе данных.

Нет никаких средств, чтобы база данных отправляла уведомления в приложение. Приложению необходимо опросить базу данных, чтобы проверить наличие обновлений, а затем соответствующим образом обработать обновления.

0 голосов
/ 16 сентября 2010

Если под «обновлениями базы данных» вы подразумеваете какое-либо обновление какого-либо приложения, вам не повезло: это не выполнимо.

Если, однако, вы имеете в виду изменения, сделанные вашим приложением, это легко: каждый раз, когда вы обновляете БД и событие, и обработчики реагируют на событие.

...