我从this MSDN page中提取了一个示例,并且几乎逐字地使用了它。运行时代码编译正确但changeCount
无限增加,无论是否实际对返回的数据进行了更改。实际发生的更改dataGridView1
正确反映了更改。为什么我的SqlDependency
看起来像是在循环中发射,即使显然没有变化?
这是来源:
#region Using directives
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Text;
using System.Windows.Forms;
#endregion
namespace PreAllocation_Check
{
public partial class Form1 : Form
{
int changeCount = 0;
const string tableName = "MoxyPosition";
const string statusMessage = "Last: {0} - {1} changes.";
DataSet dataToWatch = null;
SqlConnection MoxyConn = null;
SqlCommand SQLComm = null;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
if (CanRequestNotifications())
{
SqlDependency.Start(GetConnectionString());
if (MoxyConn == null)
MoxyConn = new SqlConnection(GetConnectionString());
if (SQLComm == null)
{
SQLComm = new SqlCommand(GetSQL(), MoxyConn);
SqlParameter prm = new SqlParameter("@Quantity", SqlDbType.Int);
prm.Direction = ParameterDirection.Input;
prm.DbType = DbType.Int32;
prm.Value = 100;
SQLComm.Parameters.Add(prm);
}
if (dataToWatch == null)
dataToWatch = new DataSet();
GetData();
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
SqlDependency.Stop(GetConnectionString());
if (MoxyConn != null)
MoxyConn.Close();
}
private bool CanRequestNotifications()
{
try
{
SqlClientPermission SQLPerm = new SqlClientPermission(PermissionState.Unrestricted);
SQLPerm.Demand();
return true;
}
catch
{
return false;
}
}
private string GetConnectionString()
{
return "server=***;database=***;user id=***;password=***";
}
private void GetData()
{
dataToWatch.Clear();
SQLComm.Notification = null;
SqlDependency SQLDep = new SqlDependency(SQLComm);
SQLDep.OnChange += new OnChangeEventHandler(SQLDep_OnChange);
using (SqlDataAdapter adapter = new SqlDataAdapter(SQLComm))
{
adapter.Fill(dataToWatch, tableName);
dataGridView1.DataSource = dataToWatch;
dataGridView1.DataMember = tableName;
}
}
private string GetSQL()
{
return "SELECT PortID, CONVERT(money, SUM(PreAllocPos), 1) AS PreAllocation, CONVERT(money, SUM(AllocPos), 1) AS Allocation, CONVERT(money, SUM(PreAllocPos) - SUM(AllocPos), 1) AS PreLessAlloc " +
"FROM MoxyPosition " +
"WHERE CONVERT(money, PreAllocPos, 1) <> CONVERT(money, AllocPos, 1) " +
"GROUP BY PortID " +
"ORDER BY PortID ASC;";
}
void SQLDep_OnChange(object sender, SqlNotificationEventArgs e)
{
ISynchronizeInvoke i = (ISynchronizeInvoke)this;
if (i.InvokeRequired)
{
OnChangeEventHandler tempDelegate = new OnChangeEventHandler(SQLDep_OnChange);
object[] args = { sender, e };
i.BeginInvoke(tempDelegate, args);
return;
}
SqlDependency SQLDep = (SqlDependency)sender;
SQLDep.OnChange -= SQLDep_OnChange;
changeCount++;
DateTime LastRefresh = System.DateTime.Now;
label1.Text = String.Format(statusMessage, LastRefresh.TimeOfDay, changeCount);
GetData();
}
}
}
编辑:值得注意的是,我想要运行此数据库的数据库当前没有启用Broker服务,因此为了测试我的代码,我备份了我的目标数据库并使用新名称,然后针对它运行ALTER DATABASE my_db_name SET ENABLE_BROKER
。我的所有测试都在这个备用数据库上,这意味着我是唯一的用户。
答案 0 :(得分:4)
这是一个老问题,但问题是您的查询不符合要求。
简答:
将架构名称添加到表"FROM DBO.MoxyPosition " +
更长的回答:
您可以看到list of requirements here,它与创建索引视图的非常相似。注册SQL依赖项时,如果它无效,通知会立即触发,让您知道它无效。当你考虑它时,这是有道理的,因为Visual Studio如何知道SQL Engine的内部要求是什么?
因此,在SQLDep_OnChange
函数中,您需要查看原因所引发的依赖项。原因在于e
变量(信息,来源和类型)。有关事件对象的详细信息,请访问:
针对您的具体情况,请注意MS describes Type
属性的{{3}}:
Gets a value that indicates whether this notification is generated
because of an actual change, OR BY THE SUBSCRIPTION.
答案 1 :(得分:1)
我有类似的问题。原来做SELECT * FROM dbo.MyTable
导致更新不断发生。更改为SELECT Id, Column1, Column2 FROM dbo.MyTable
解决了问题。
您的查询中似乎没有使用*
,但您可以尝试简化查询以查看是否仍有问题。
答案 2 :(得分:0)
我没有这方面的答案,但你确实打破了至少一条规则:http://msdn.microsoft.com/en-us/library/aewzkxxh.aspx
当您未能使用两部分表名时。将MoxyPosition更改为dbo.MoxyPosition并查看上面链接的规则。我希望它有所帮助,但有些东西告诉我其他东西在这里有问题。
答案 3 :(得分:0)
查看处理程序中SqlNotificationEventArgs的类型(定义如下)。如果您看到它达到数百次并且Type每次都是Subscribe,那么您的SQL语句是错误的 - 请参阅其他帖子中的指南
private void HandleOnChange(object sender, SqlNotificationEventArgs e)
{
...
var someType = e.Type; /*If it is Subscribe, not Change, then you may have your SQL statement wrong*/
...
}