7

この MSDN ページから例を引っ張ってきて、ほぼそのまま使用しました。実行すると、コードは適切にコンパイルされますが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 Service が有効になっていないことに注意してください。そのため、コードをテストするために、ターゲットデータベースをバックアップして新しい名前で復元し、それALTER DATABASE my_db_name SET ENABLE_BROKERに対して実行しました。私のテストはすべてこの代替データベースで行われました。つまり、私はそのデータベースの唯一のユーザーです。

4

4 に答える 4

4

これは古い質問ですが、問題はクエリが要件を満たしていないことです。

簡単な答え:
テーブルにスキーマ名を追加します"FROM DBO.MoxyPosition " +

より長い回答:ここで要件
のリストを確認できます。これは、インデックス付きビューを作成する場合と非常によく似ています。SQL 依存関係が登録されると、それが無効である場合、通知がすぐに発生し、無効であることを知らせます。Visual Studio は、SQL エンジンの内部要件をどのように知ることができるのでしょうか。

したがって、関数では、依存関係が発生した理由SQLDep_OnChangeを確認する必要があります。その理由は変数 (情報、ソース、およびタイプ) にあります。イベント オブジェクトの詳細は、次の場所にあります。e

特定のケースについては、 MS がプロパティをどのように説明しているTypeかに注意してください。

Gets a value that indicates whether this notification is generated 
because of an actual change, OR BY THE SUBSCRIPTION.
于 2012-08-17T20:38:14.790 に答える
1

同様の問題がありました。行うSELECT * FROM dbo.MyTableと、更新が絶えず発生する原因となっていることが判明しました。問題をSELECT Id, Column1, Column2 FROM dbo.MyTable修正しました。

クエリで使用しているようには見えませんが*、クエリを単純化して、まだ問題があるかどうかを確認してください。

于 2011-07-27T03:32:26.923 に答える
0

これに対する答えはありませんが、ここで少なくとも1つのルールに違反しました:http://msdn.microsoft.com/en-us/library/aewzkxxh.aspx

2つの部分からなるテーブル名を使用できなかった場合。MoxyPositionをdbo.MoxyPositionに変更し、上記のリンクされているルールを確認します。お役に立てば幸いですが、ここで何か他の問題が発生していることがわかります。

于 2011-07-12T17:37:05.163 に答える
0

SqlNotificationEventArgs の Type がハンドラーにあるものを確認してください (以下のように定義されています)。何百回もヒットし、毎回 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*/
...
}
于 2013-10-17T14:51:25.047 に答える