ASP.NET中的SqlDependency

Dae*_*ohn 4 c# sql-server asp.net domain-driven-design

我在SQL Dependency对象上创建了以下封装:

public class DependencyTracker
    {
        private SqlDependency _SQLDependency = null;

        public string ConnectionString
        { get; private set; }

        public string CommandNotifier
        { get; private set; }

        public delegate void Refresh();
        public event Refresh OnRefresh;

        public DependencyTracker(string connectionString, string commandNotifier)
        {
            ConnectionString = connectionString;
            CommandNotifier = commandNotifier;
        }

        public void StartDependency()
        {
            SqlDependency.Start(ConnectionString);
        }

        public void StopDependency()
        {
            SqlDependency.Stop(ConnectionString);
        }

        public void TrackForChanges()
        {
            using (SqlConnection sqlConn = new SqlConnection(ConnectionString))
            {
                sqlConn.Open();
                using (SqlCommand sqlCommand = new SqlCommand(CommandNotifier, sqlConn))
                {
                    sqlCommand.CommandType = CommandType.StoredProcedure;
                    _SQLDependency = new SqlDependency(sqlCommand);
                    _SQLDependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
                    sqlCommand.ExecuteReader();
                }
            }
        }

        void dependency_OnChange(object sender, SqlNotificationEventArgs e)
        {
            SqlDependency sqlDependency = (SqlDependency)sender;
            sqlDependency.OnChange -= dependency_OnChange;

            if (OnRefresh != null)
            {
                OnRefresh();
            }
        }

        public bool HasChanges
        {
            get
            {
                return _SQLDependency.HasChanges;
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

这不是原创作品,而是基于这篇文章.从我的存储库中我执行以下操作:

public bool Updatexxx(Ixxx xsxs)
        {
            try
            {
                SqlConnection sqlConn = new SqlConnection(_ConnectionString);
                sqlConn.Open();
                ...

                bool result = sqlComm.ExecuteNonQuery() == 1;

                _ResetEvent.WaitOne();

                return result;
            }
            catch ...
            catch ...
        }
Run Code Online (Sandbox Code Playgroud)

回调是

public void RefreshData()
        {
            FindAllxxx();
            _ResetEvent.Set();
        }
Run Code Online (Sandbox Code Playgroud)

public HashSet<Iddd> Finddadas()
        {
            DependencyTracker tracker = _Container.Resolve<DependencyTracker>("dada");
            UnityHashSet<IT24Route> hash = _Container.Resolve<UnityHashSet<dadas>>("Tdsadas");
            if (tracker.HasChanges || hash.Count == 0)
            {
                hash = new UnityHashSet<dsda>(_Container);
                hash.ImportHashSet(FindAlldsdsNonCached());
                _Container.RegisterInstance<UnityHashSet<dsds>>("dasda", hash);
                tracker.TrackForChanges();
            }
            return hash;
        }
Run Code Online (Sandbox Code Playgroud)

和FindAllXXXNonCached()从数据库中进行实际选择.如你所见,我正在缓存一切.我的问题是为什么这不起作用.症状:从dependecy tracker调用两次回调然后阻塞.我实现了这个,因为我的通知是在页面刷新开始后发生的.我试图设置手动重置事件以给出通知机会,然后设置手动重置事件并刷新UI.正如我所说,经过OnChange两次后,它会冻结.我能做什么?Dependency Tracker是在Unity容器中注册的实例,Repository是类型注册的.

Rem*_*anu 6

void dependency_OnChange(object sender, SqlNotificationEventArgs e)
Run Code Online (Sandbox Code Playgroud)

您应该检查SqlNotificationEventArgs并查看您的通知,数据更改或其他内容.检查信息是否为插入/更新/删除.检查是否为数据.检查类型是否更改.

最有可能的是,您的查询会立即发出信号,表明它不符合对查询通知施加限制.是的,我知道链接指向索引视图,如果您想了解原因,请阅读神秘通知.

您在Update等待_ResetEvent和回调信号_ResetEvent之间也存在竞争条件.T1呼叫更新.同时,数据中发生了不相关的更新,并且调用了回调._ResetEvent已设置.T1完成更新并等待_ResteEvent,它会发出信号,因此它会继续.调用者假定回调发生了自己的更新并刷新了缓存,但事实并非如此.

第二个更严重的问题是在存在事务时代码是不正确的.UpdateXXX假定其自身更新的回调将立即发生并等待它.查询通知将仅在更新提交后由引擎传递,因此当存在TransactionScope时,UpdateXXX方法将阻止等待直到UpdateXXX返回(实时死锁)时才会发出通知.

还不清楚TrackForChanges的目的是什么.您正在读取SqlDataReader(sqlCommand.ExecuteReader)但忽略结果.使用查询通知,您可以提交查询,阅读结果,并在结果发生变化时收到通知.

最后,永远不要读取SqlDependency通知回调中的数据.