【发布时间】:2010-09-16 03:43:40
【问题描述】:
我有一个 C# 程序可以查询 SQL Server 数据库的某些值。
目前,应用程序每分钟查询一次数据库以确保表是最新的。
我希望能够做的是查询仅在数据库已更改/更新时完成。当数据库中的某些内容发生更新时,如何通知我的程序?
谢谢
【问题讨论】:
标签: c# sql-server visual-studio-2005 notifications
我有一个 C# 程序可以查询 SQL Server 数据库的某些值。
目前,应用程序每分钟查询一次数据库以确保表是最新的。
我希望能够做的是查询仅在数据库已更改/更新时完成。当数据库中的某些内容发生更新时,如何通知我的程序?
谢谢
【问题讨论】:
标签: c# sql-server visual-studio-2005 notifications
轮询数据库不是很优雅的解决方案。
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
这里是如何启用服务代理(请注意,您将拥有数据库的排他性 - 最好在重新启动 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
【讨论】:
如果您使用的是 SQL Server 2005 及更高版本,则可以考虑使用 SqlDependency 对象。
它表示应用程序和 SQL Server 2005 实例之间的查询通知依赖关系。
应用程序可以创建 SqlDependency 对象并注册以通过 OnChangeEventHandler 事件处理程序接收通知。
Refer this link on MSDN for more information
但是,请注意 MS 反对使用它的警告。建议有一个缓存层,然后使用 SQLDependency 与该层协调。
SqlDependency 被设计用于 ASP.NET 或中间层服务,其中有相对少量的服务器对数据库具有活动的依赖项。它不是为在客户端应用程序中使用而设计的,在这些应用程序中,成百上千的客户端计算机将为单个数据库服务器设置 SqlDependency 对象。
【讨论】:
要在更新某些记录时获得通知,请避免应用程序查询您使用 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# 数据表保持最新,您可以从事件处理程序中获取最新数据。
【讨论】:
我希望能够做的是查询仅在数据库已更改/更新时完成。当数据库中的某些内容更新时,我如何通知我的程序。
数据库没有任何方法可以将通知推送到应用程序。应用程序需要轮询数据库以检查更新,然后适当地处理更新。
【讨论】:
如果“对数据库的更新”是指任何应用程序的任何更新,那么你就不走运了:这是不可行的。
但是,如果您指的是应用程序所做的更改,这很容易:每次更新数据库引发和事件并让处理程序响应事件时。
【讨论】: