Есть ли способ заставить SQL Server 2005 перезвонить подключенному приложению, чтобы подключенное приложение узнало, когда запись в таблице имеет поле, измененное другим приложением, использующим ту же базу данных?
Простой пример - два экземпляра одного и того же приложения, подключенных к одной и той же таблице в одной базе данных. Когда один экземпляр приложения вносит изменения в таблицу, другой экземпляр получает уведомление о том, что что-то изменилось, и может запросить изменения в базе данных.
UPDATE
Спасибо большое за помощь. Я бы никогда не узнал, чтобы искать класс SqlDependency. Я следовал инструкции на этой странице http://msdn.microsoft.com/en-us/a52dhwx7.aspx при создании демонстрационной демонстрации SqlDependency. Однако я не смог заставить это работать. Я никогда не вижу, чтобы вызывалось событие OnChange.
Я также безуспешно пытался изменить свое собственное приложение, используя инструкции в качестве руководства. Я включил код из моего собственного приложения ниже. По сути, таблица Position имеет поле PositionID вместе с полями LocationX и LocationY. Я написал другое приложение, которое позволяет мне обновлять поле LocationX данной строки.
Что мне не хватает? Почему изменения базы данных не вызовут мой четный обработчик?
ОБНОВЛЕНИЕ № 2
Также обратите внимание, что я использую жестко закодированную строку SQL для своей команды. Я бы предпочел не использовать закомментированный оператор LINQ. Считается ли правильным использовать LINQ таким образом для генерации строки SQL, которая будет использоваться для построения команды?
ОБНОВЛЕНИЕ № 3
Так что мне удалось выяснить, что не так с моим кодом ниже. По-видимому, вам нужно выполнить команду один раз, чтобы был кэш данных, иначе сервер не знает, когда вас уведомить? Я добавил в строку для выполнения DataAdapter.Fill () с моим SqlCommand, и теперь событие, кажется, срабатывает, когда ожидается.
Что подводит меня к моей следующей проблеме. Событие SqlDependency.OnChange только сообщает, что что-то изменилось. Как я могу узнать из моего старого DataSet и нового DataSet, каковы построчные изменения?
Конечно, я мог бы снова прочитать весь запрос и обновить все свои структуры данных, но это кажется чрезмерным.
Я могу вызвать DataContext.Refresh () и заставить его выполнять все обновления моих структур данных, но, похоже, это не вызывает никаких событий, генерируемых DataContext OnChanging (). Кажется, что Refresh () фактически разрушает все мои структуры и создает новые. Поэтому я никогда не могу понять, что изменилось.
У кого-нибудь есть рекомендации?
public partial class MainForm : Form
{
private ArpPhase2DbContextDataContext db = null;
private SqlConnection connection = null;
private SqlCommand command = null;
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
this.canRequestNotifications();
this.db = ArpPhase2DbContextDataContext.Instance;
this.setupSqlDependency();
}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
SqlDependency.Stop(this.db.Connection.ConnectionString);
if (this.connection != null)
{
this.connection.Close();
}
this.db.SubmitChanges();
}
private bool canRequestNotifications()
{
try
{
SqlClientPermission perm = new SqlClientPermission(PermissionState.Unrestricted);
perm.Demand();
return true;
}
catch
{
return false;
}
}
private void setupSqlDependency()
{
// Remove any existing dependency connection, then create a new one.
SqlDependency.Stop(this.db.Connection.ConnectionString);
SqlDependency.Start(this.db.Connection.ConnectionString);
if (this.connection == null)
{
this.connection = new SqlConnection(this.db.Connection.ConnectionString);
}
if (this.command == null)
{
var sql = (from position in this.db.Positions
select position);
//string commandString = sql.ToString();
string commandString = "SELECT * FROM Positions;";
this.command = new SqlCommand(commandString, connection);
}
this.getData();
}
private void getData()
{
// Make sure the command object does not already have
// a notification object associated with it.
this.command.Notification = null;
// Create and bind the SqlDependency object
// to the command object.
SqlDependency dependency = new SqlDependency(this.command);
dependency.OnChange += new OnChangeEventHandler(this.dependency_OnChange);
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
// This event will occur on a thread pool thread.
// Updating the UI from a worker thread is not permitted.
// The following code checks to see if it is safe to
// update the UI.
ISynchronizeInvoke i = (ISynchronizeInvoke)this;
// If InvokeRequired returns True, the code
// is executing on a worker thread.
if (i.InvokeRequired)
{
// Create a delegate to perform the thread switch.
OnChangeEventHandler del = new OnChangeEventHandler(this.dependency_OnChange);
object[] args = { sender, e };
// Marshal the data from the worker thread
// to the UI thread.
i.BeginInvoke(del, args);
return;
}
// Remove the handler, since it is only good
// for a single notification.
SqlDependency dependency = (SqlDependency)sender;
dependency.OnChange -= this.dependency_OnChange;
// Add information from the event arguments to the list box
// for debugging purposes only.
Console.WriteLine("Info: {0}, Source: {1}, Type: {2}", e.Info.ToString(),
e.Source.ToString(), e.Type.ToString());
// Rebind the dependency.
this.setupSqlDependency();
}
}