2011-12-22 65 views
12

我不知道为什么SqlCacheDependency对象的HasChanged值最初从命令执行返回为false,但在数据从数据库返回后几乎立即返回,值更改为true。为什么我的SqlCacheDependency HasChanged会变回false,但在更改为true后几乎立即变为false?

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

存储过程:

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 

它调用存储过程中的问题,失败的代码:

,工程

 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方法重载,

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; 

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

你可以看到,当“非工作”的数据最初检索,一切都OK:

enter image description here

而是介于随机超出该点,在这种情况下,刚刚步入下一个方法

enter image description here

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

回答

6

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

在这篇文章中Creating a Query for Notification,我DID冲刷多次,它明确规定:

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。

我的数据集现在正确缓存和保留数据,没有错误的变化指标。

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; 

重要

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

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

+0

我会试试它,但我认为这不太可能,因为param哈希仅用于构建创建缓存项的密钥名称。 – 2011-12-27 00:38:39

+1

@TheEvilGreebo:对不起,我觉得我没有足够的沟通。我认为问题是这行代码'新的SqlParameter(“@ ER_ID”,_eR_ID)'。这将整个_eR_ID对象传递给参数,我不确定它是如何将它转换为Sql的值(我怀疑它在对象上调用了ToString())。之前在代码中使用_eR_ID.Value,所以我认为您需要的最小更改是'new SqlParameter(“@ ER_ID”,_eR_ID.Value)'。 – 2011-12-27 00:51:58

+0

哦,我明白你的意思了。那么_eR_ID是一个SqlInt32 - 所以人们会认为使用它初始化一个新的SqlParm不会引起问题,但它值得一试! – 2011-12-27 01:47:51

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/changing-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部分名称表。在他的情况下,这个建议解决了这个问题。在查看他的代码后,我注意到主要区别在于等待打开连接对象,直到命令对象和依赖对象创建后。我唯一的假设是隐藏的(我还没有开始反射器检查,所以只有一个假设),Connection对象以不同的方式打开,或者事件和命令的顺序发生不同,因为这种关联。

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

我希望这可以帮助别人类似的问题还有。

+0

我不认为这是正确的。顺序是重要的,但打开连接时不是。 – 2014-12-13 14:44:45

相关问题