我有一个C#程序,它在SQL Server数据库中查询某些值。
目前,应用程序每分钟查询一次数据库,以确保该表是最新的。
我希望能够做的是只在数据库被更改/更新时才进行查询。如何在数据库中更新某些内容后如何通知我的程序?
由于
答案 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)
如果通过“对数据库的更新”表示任何应用程序的任何更新,那么您运气不好:它不可行。
但是,如果您的意思是应用程序所做的更改,则很容易:每次更新数据库引发和事件并让处理程序响应事件。