数据库更新后如何通知我的程序?

时间:2010-09-16 03:43:40

标签: c# sql-server visual-studio-2005 notifications

我有一个C#程序,它在SQL Server数据库中查询某些值。

目前,应用程序每分钟查询一次数据库,以确保该表是最新的。

我希望能够做的是只在数据库被更改/更新时才进行查询。如何在数据库中更新某些内容后如何通知我的程序?

由于

5 个答案:

答案 0 :(得分:9)

轮询数据库不是很优雅的解决方案。

来自ADO.NET的

SqlDependency对您的情况很有用。它不使用轮询而是使用通知机制。通知由数据库中的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 server后执行此操作): http://blogs.sftsrc.com/stuart/archive/2007/06/13/42.aspx (断开链接)

可能的替代链接:http://technet.microsoft.com/en-us/library/ms166086(v=sql.105).aspx

答案 1 :(得分:4)

如果您使用的是SQL Server 2005及更高版本,则可以考虑使用SqlDependency对象。

它表示应用程序与SQL Server 2005实例之间的查询通知依赖关系。

应用程序可以创建SqlDependency对象并注册以通过OnChangeEventHandler事件处理程序接收通知。

Refer this link on MSDN for more information

但是,请注意MS对其使用的警告。建议使用缓存层,然后与该层协调使用SQLDependency。

SqlDependency旨在用于ASP.NET或中间层服务,其中存在相对较少数量的服务器,这些服务器具有对数据库的活动依赖性。它不是设计用于客户端应用程序,其中数百或数千台客户端计算机将为单个数据库服务器设置SqlDependency对象。

答案 2 :(得分:3)

要在更新某条记录时获取通知,请避免应用程序查询您使用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#Datatable保持最新,那么您就可以从事件处理程序中获取新数据。

答案 3 :(得分:2)

  

我希望能够做的是只在数据库被更改/更新时才进行查询。当数据库中的某些内容更新时,我如何通知我的程序。

数据库没有任何方法将通知推送到应用程序。应用程序需要轮询数据库以检查更新,然后适当地处理更新。

答案 4 :(得分:-2)

如果通过“对数据库的更新”表示任何应用程序的任何更新,那么您运气不好:它不可行。

但是,如果您的意思是应用程序所做的更改,则很容易:每次更新数据库引发和事件并让处理程序响应事件。