简体   繁体   English

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

[英]How can I notify my program when the database has been updated?

I have a C# program that queries the SQL Server database for some values. 我有一个C#程序,它在SQL Server数据库中查询某些值。

Currently the application queries the database every minutes to make sure that the table is up to date. 目前,应用程序每分钟查询一次数据库,以确保该表是最新的。

What I would like to be able to do is that the query is only done when the database has been changed / updated. 我希望能够做的是只在数据库被更改/更新时才进行查询。 How do I notify my program when something has been updated in the database? 如何在数据库中更新某些内容后如何通知我的程序?

Thanks 谢谢

Polling database is not very elegant solution. 轮询数据库解决方案不是很优雅。

SqlDependency from ADO.NET will be useful in your case. 来自ADO.NET的SqlDependency对您的情况很有用。 It does not use polling but notification mechanism. 它不使用轮询而是使用通知机制。 The notifications are provided by Service Broker in your database, so will need to enable this service in your databse. 通知由数据库中的Service Broker提供,因此需要在数据库中启用此服务。 The OnChange event will raise when specified table changes(update, delete, insert..) 当指定的表更改(更新,删除,插入..)时, OnChange事件将引发

Here is an example how to use SqlDependency: 以下是如何使用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);
}

from http://msdn.microsoft.com/en-us/library/62xk7953.aspx 来自http://msdn.microsoft.com/en-us/library/62xk7953.aspx

Here is how to enable Service Broker(note that you will have exclusiveness on the database to do that - best do it after restart of the sql server): http://blogs.sftsrc.com/stuart/archive/2007/06/13/42.aspx (Broken link) 以下是如何启用Service Broker(请注意,您将在数据库上具有独占性来执行此操作 - 最好在重新启动sql server之后执行此操作): http //blogs.sftsrc.com/stuart/archive/2007/06/ 13 / 42.aspx 断开 链接)

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

If you are on SQL Server 2005 and above, you can consider using the SqlDependency object. 如果您使用的是SQL Server 2005及更高版本,则可以考虑使用SqlDependency对象。

It represents a query notification dependency between an application and an instance of SQL Server 2005. 它表示应用程序与SQL Server 2005实例之间的查询通知依赖关系。

An application can create a SqlDependency object and register to receive notifications via the OnChangeEventHandler event handler. 应用程序可以创建SqlDependency对象并注册以通过OnChangeEventHandler事件处理程序接收通知。

Refer this link on MSDN for more information 有关详细信息,请参阅MSDN上的此链接

However, do note the caveat that MS puts against its use. 但是,请注意MS对其使用的警告。 It is advised to have a caching layer and then use SQLDependency in coordination with that layer . 建议使用缓存层,然后与该层协调使用SQLDependency。

SqlDependency was designed to be used in ASP.NET or middle-tier services where there is a relatively small number of servers having dependencies active against the database. SqlDependency旨在用于ASP.NET或中间层服务,其中存在相对较少数量的服务器,这些服务器具有对数据库的活动依赖性。 It was not designed for use in client applications, where hundreds or thousands of client computers would have SqlDependency objects set up for a single database server. 它不是设计用于客户端应用程序,其中数百或数千台客户端计算机将为单个数据库服务器设置SqlDependency对象。

To get a notify when some record is updated, avoid the application to query the table you cab use TableDependency component (in your specific case SqlTableDependency ). 要在更新某些记录时获取通知,请避免应用程序查询您使用TableDependency组件的表(在您的特定情况下为SqlTableDependency )。 Here is an example: 这是一个例子:

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;
    }

The event handler is triggered for every INSERT UPDATE or DELETE operation done on the table, reporting you the modified value. 在表上执行的每个INSERT UPDATE或DELETE操作都会触发事件处理程序,并向您报告修改后的值。 So, in case you are interested to keep your C# Datatable up to date, you simple can get the fresh data from the event handler. 因此,如果您有兴趣让C#Datatable保持最新,那么您可以从事件处理程序中获取新数据。

What I would like to be able to do is that the query is only done when the database has been changed/updated.How do i notify my program when some thing updated in database. 我希望能够做的是只在数据库被更改/更新时才进行查询。当数据库中的某些内容更新时,我如何通知我的程序。

There isn't any means of the database pushing notifications to the application. 数据库没有任何方法将通知推送到应用程序。 The application needs to poll the database to check for updates, and then deal with the updates appropriately. 应用程序需要轮询数据库以检查更新,然后适当地处理更新。

If by "updates to the database" you mean any update by any application, you're out of luck: it's not doable. 如果通过“对数据库的更新”表示任何应用程序的任何更新,那你就不走运了:这是不可行的。

If, however, you mean changes made by your app, it's easy: every time you update the DB raise and event and have handlers respond to the event. 但是,如果您的意思是应用程序所做的更改,则很容易:每次更新数据库引发和事件并让处理程序响应事件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM