c# - 使用 LINQ-to-SQL 跟踪数据库的外部更改

标签 c# sql database linq linq-to-sql

有没有办法让 SQL Server 2005 回调连接的应用程序,这样连接的应用程序就会知道表中的记录何时被使用同一数据库的另一个应用程序修改了字段?

一个简单的例子是同一个应用程序的两个实例连接到同一个数据库中的同一个表。当应用程序的一个实例对表进行更改时,另一个实例将收到通知,告知发生了某些更改,并能够查询数据库以获取更改。

更新

非常感谢到目前为止的帮助。我什至不知道要查找 SqlDependency 类。我已按照此页面上的说明进行操作 http://msdn.microsoft.com/en-us/a52dhwx7.aspx在创建 SqlDependency 测试演示时。但是,我无法让它工作。我从未见过调用 OnChange 事件。

我也曾尝试使用说明作为指南来修改我自己的应用程序,但没有成功。我在下面包含了我自己的应用程序中的代码。基本上,Position 表有一个 PositionID 字段以及一个 LocationX 和 LocationY 字段。我编写了另一个应用程序,允许我更新给定行的 LocationX 字段。

我错过了什么?为什么数据库更改不会触发我的偶数处理程序?

更新#2

另请注意,我正在为我的命令使用硬编码的 SQL 字符串。我宁愿不使用注释掉的 LINQ 语句。以这种方式使用 LINQ 来生成将用于构建命令的 SQL 字符串是否被认为可以?

更新 #3

所以我设法找出我下面的代码出了什么问题。显然你必须执行一次命令所以会有数据缓存,否则服务器不知道什么时候通知你?我添加了一行以使用我的 SqlCommand 执行 DataAdapter.Fill() 并且该事件现在似乎在预期时触发。

这让我想到了下一个问题。 SqlDependency.OnChange 事件仅让您知道某些内容已更改。我如何从我的旧数据集和新数据集中找出逐行更改的内容?

我当然可以再次阅读整个查询并更新我所有的数据结构,但这似乎太过分了。

我可以调用 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();
    }
  }

最佳答案

SQL Server 可以用 Query Notifications 做到这一点. L2S 中没有内置任何东西来支持这一点,但也没有什么可以阻止您在同一应用程序中在 L2S 之外使用它。

关于c# - 使用 LINQ-to-SQL 跟踪数据库的外部更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1910544/

相关文章:

c# - 无法在 Visual Studio 2010 + Resharper 中键入某些方括号

c# - 在 WPF 中自托管 WCF

SQL xml 列组和计数元素数据

java - 为什么这个 HQL 无效?

sql - 在 SQL Server 中查找当前年份日期给定的上一年的同一天

mysql - Django多个外键多次引用同一个表?

database - 如何从 Django 异步处理数据库写入(可能使用消息队列)?

c# - 本地化组名

java - 如何持久化具有现有持久化对象的 transient 实体?

c# - 路径错误中的非法字符