12

我无法弄清楚为什么HasChanged我的SqlCacheDependency对象的值最初从命令执行中返回为假,但是在它从数据库返回后几乎立即的某个地方,该值更改为真。

有时这发生在项目甚至插入缓存之前,导致缓存立即丢弃它,有时是在插入之后,我可以抓住一个枚举器,它看到缓存中的键,但在我什至循环到该项目之前缓存它已被删除。

存储过程:

ALTER PROCEDURE [dbo].[ntz_dal_ER_X_Note_SelectAllWER_ID]
        @ER_ID int
AS
BEGIN
    SELECT
        ER_X_Note_ID,
        ER_ID,
        Note_ID
    FROM dbo.ER_X_Note e
    WHERE
        ER_ID = @ER_ID
END

数据库是 MS SQL Server 2008,启用了代理服务,并且某些输出会缓存并保持缓存。例如,这个工作得很好:

ALTER PROC [dbo].[ntz_dal_GetCacheControllerByEntityName] (
    @Name varchar(50)
) AS
BEGIN
    SELECT 
        CacheController_ID,
        EntityName,
        CacheEnabled,
        Expiration
    From dbo.CacheController cc
    WHERE   EntityName = @Name
END

调用有问题的 SPROC 失败的代码:

    DataSet toReturn;
    Hashtable paramHash = new Hashtable();
    paramHash.Add("ER_ID", _eR_ID.IsNull ? null : _eR_ID.Value.ToString());
    string cacheName = BuildCacheString("ntz_dal_ER_X_Note_SelectAllWER_ID", paramHash);
    toReturn = (DataSet)GetFromCache(cacheName);
    if (toReturn == null)
    {

        // Set up parameters (1 input and 0 output)
        SqlParameter[] arParms = {
                new SqlParameter("@ER_ID", _eR_ID),
            };
        SqlCacheDependency scd;

        // Execute query.
        toReturn = _dbTransaction != null 
            ? _dbConnection.ExecuteDataset(_dbTransaction, "dbo.[ntz_dal_ER_X_Note_SelectAllWER_ID]", out scd, arParms) 
            : _dbConnection.ExecuteDataset("dbo.[ntz_dal_ER_X_Note_SelectAllWER_ID]", out scd, arParms);

        AddToCache(cacheName, toReturn, scd);
    }

    return toReturn;

有效的代码

        const string sprocName = "ntz_dal_GetCacheControllerByEntityName";
        string cacheControlPrefix = "CacheController_" + CachePrefix;
        CacheControl controller = (CacheControl)_cache[cacheControlPrefix];
        if (controller == null)
        {
            try
            {
                SqlParameter[] arParms = {
                                             new SqlParameter("@Name", CachePrefix),
                                         };
                SqlCacheDependency sqlCacheDependency;

                // Execute query.
                DataSet result = _dbTransaction != null
                                     ? _dbConnection.ExecuteDataset(_dbTransaction, sprocName, out sqlCacheDependency, arParms)
                                     : _dbConnection.ExecuteDataset(sprocName, out sqlCacheDependency, arParms);

                controller = result.Tables[0].Rows.Count == 0
                                 ? new CacheControl(false)
                                 : new CacheControl(result.Tables[0].Rows[0]);

                _cache.Insert(cacheControlPrefix, controller, sqlCacheDependency);
            }
            catch (Exception ex)
            {
                // if sproc retreival fails cache the result of false so we don't keep trying
                // this is the only case where it can be added with no expiration date
                controller = new CacheControl(false);

                // direct cache insert, no dependency, no expiration, never try again for this entity
                if (HttpContext.Current != null && UseCaching && _cache != null) _cache.Insert(cacheControlPrefix, controller);
            }
        }
        return controller;

AddToCache方法被重载并且有更多的测试;工作方法中的直接_cache.Insert是绕过那些其他测试。工作代码有助于确定数据库缓存是否应该发生。

您可以看到,最初检索“非工作”数据时,一切正常:

在此处输入图像描述

但是在那一点之外的某个地方,在这种情况下,只是进入下一个方法

在此处输入图像描述

然而数据根本没有改变;我是唯一一个接触这个数据库实例的人。

4

3 回答 3

6

这真的,真的很简单,太简单了,我完全忽略了它。

在这篇文章为 Notification 创建一个查询,我了多次搜索,它清楚地指出:

SET 选项设置

当在通知请求下执行 SELECT 语句时,提交请求的连接必须具有连接的选项集,如下所示:

ANSI_NULLS ON
ANSI_PADDING ON
ANSI_WARNINGS ON
CONCAT_NULL_YIELDS_NULL ON
QUOTED_IDENTIFIER ON
NUMERIC_ROUNDABORT OFF
ARITHABORT ON

好吧,我读了又读了 sproc,但我仍然没有看到 ANSI_NULLS 和 QUOTED_IDENTIFIER 都是“OFF”,而不是 ON。

我的数据集现在正在正确缓存和保留数据,而不会出现错误的更改指示。

于 2011-12-27T13:47:11.547 回答
1

我有预感,问题出在你的_eR_ID. 我认为您应该尝试向失败的过程添加一个局部变量,该过程使用 _eR_ID 的不可能值,例如 -1。我从不相信涉及空值时会发生什么,我认为这可能是您问题的根源。

这是我建议尝试的修改版本:

DataSet toReturn;
Hashtable paramHash = new Hashtable();

int local_er_ID = eR_ID.IsNull ? -1 : _eR_ID.Value;
paramHash.Add("ER_ID", local_eR_ID.ToString());

string cacheName = BuildCacheString("ntz_dal_ER_X_Note_SelectAllWER_ID", paramHash);
toReturn = (DataSet)GetFromCache(cacheName);
if (toReturn == null)
{

    // Set up parameters (1 input and 0 output)
    SqlParameter[] arParms = {
            new SqlParameter("@ER_ID", local_eR_ID),
        };
    SqlCacheDependency scd;

    // Execute query.
    toReturn = _dbTransaction != null 
        ? _dbConnection.ExecuteDataset(_dbTransaction, "dbo.[ntz_dal_ER_X_Note_SelectAllWER_ID]", out scd, arParms) 
        : _dbConnection.ExecuteDataset("dbo.[ntz_dal_ER_X_Note_SelectAllWER_ID]", out scd, arParms);

    AddToCache(cacheName, toReturn, scd);
}

return toReturn;

重要的

在创建上述代码时,我想我发现了问题的根源:在设置存储的 proc 参数时,您正在使用,_eR_ID但是当您设置 paramHash 时,您正在使用_eR_ID.Value.

代码重写将解决这个问题,但我怀疑这是问题的根源。

于 2011-12-26T22:11:19.287 回答
0

遇到同样的问题并在没有任何帮助的情况下在线找到相同的答案,我正在重新搜索来自分析器的 xml 无效订阅响应。

我在 msdn 支持网站上找到了一个示例,该示例的代码顺序略有不同。当我尝试它时,我意识到了问题 - 在创建命令对象和缓存依赖对象之前不要打开连接对象。这是您必须遵循的顺序,一切都会好起来的:

  1. 确保启用通知 (SqlCahceDependencyAdmin) 并首先运行 SqlDependency.Start
  2. 创建连接对象
  3. 创建命令对象并分配命令文本、类型和连接对象(构造函数、设置属性或使用 CreateCommand 的任意组合)。
  4. 创建sql缓存依赖对象
  5. 打开连接对象
  6. 执行查询
  7. 使用依赖项将项目添加到缓存。

如果您遵循此顺序,并遵循您的 select 语句中的所有其他要求,则没有任何权限问题,这将起作用!

我认为这个问题与 .NET 框架如何管理连接有关,特别是设置了哪些设置。我尝试在我的 sql 命令测试中覆盖它,但它从未奏效。这只是一个猜测 - 我所知道的是改变订单立即解决了这个问题。

我能够将它从以下到 msdn 帖子拼凑起来。

这篇文章是无效订阅的更常见原因之一,并展示了 .Net 客户端如何设置与通知所需的属性相反的属性。

https://social.msdn.microsoft.com/Forums/en-US/cf3853f3-0ea1-41b9-987e-9922e5766066/changeing-default-set-options-forced-by-net?forum=adodotnetdataproviders

然后这篇文章来自一个和我一样的用户,他将他的代码简化为最简单的格式。我的原始代码模式与他的相似。

https://social.technet.microsoft.com/Forums/windows/en-US/5a29d49b-8c2c-4fe8-b8de-d632a3f60f68/subscriptions-always-invalid-usual-suspects-checked-no-joy?forum=sqlservicebroker

然后我发现这篇文章,也是一个非常简单的问题减少,只有他是一个简单的问题 - 表格需要 2 个部分名称。在他的情况下,这个建议解决了这个问题。查看他的代码后,我注意到主要区别是等待打开连接对象,直到创建命令对象和依赖对象之后。我唯一的假设是在幕后(我还没有启动反射器来检查,所以只有一个假设)连接对象的打开方式不同,或者事件的顺序和命令发生的方式不同,因为这种关联。

https://social.msdn.microsoft.com/Forums/sqlserver/en-US/bc9ca094-a989-4403-82c6-7f608ed462ce/sql-server-not-creating-subscription-for-simple-select-query-when- using-sqlcachedependency?forum=sqlservicebroker

我希望这可以帮助其他人解决类似的问题。

于 2014-12-11T16:45:40.380 回答