5

我想为某些键存储空值,HttpRuntime.Cache因为我不想再次去数据库发现该键没有条目。

所以第一次,它进入数据库并填充缓存。目的是使用缓存数据而不是进行数据库调用来服务以下调用。

这是我正在使用的代码:

            Info info = null;
        if (HttpRuntime.Cache["Info_" + id.ToString() + "_" + quantity.ToString()] != null)
            info = HttpRuntime.Cache["Info_" + id.ToString() + "_" + quantity.ToString()] as Info;
        if (info == null)
        {
            info = (from dd in dc.Infos
                              where dd.id == id && dd.active == true && dd.quantitytooffset == quantity
                              select dd).SingleOrDefault();
            HttpRuntime.Cache.Add("Info_" + id.ToString() + "_" + quantity.ToString(), info, null, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.High, null);
        }

最后一行代码,即 HttpRuntime.Cache.Add 抛出 System.ArgumentNullException: Value cannot be null。

知道这是否可能,或者我需要使用其他数据结构来存储空值并稍后查找?

4

4 回答 4

6

您可以使用自己的“null”值放入缓存。例如,

private static Info NULL_INFO = new Info();

然后你可以在 HttpRuntime.Cache.Add 中使用它而不是 null ,然后在从缓存中检索后检查你没有得到你的 NULL_INFO

if ( info == NULL_INFO) // if you don't have equality operator overloaded, otherwise you'd better use ReferenceEquals() 
    // return empty data
else if (info == null)
    // proceed with try to load from database
于 2012-03-22T10:55:50.960 回答
1

我最近写了一篇关于null关键字经常被滥用导致这种混乱的博客文章。在您的特定情况下,我会考虑使用选项类型来指示数据的缺失或存在,而不是 null。

我有一个 Option 类型的简单实现,你可以在这里使用

用法将类似于:

if (HttpRuntime.Cache["xyz"] == null)
// Impossible to make a distinction between whether or not the cache value is missing
// or if it is present but explicitly a null value...

HttpRuntime.Cache["xyz"] = Option<String>.None();
// We have now explicitly stated that the cache contains xyz but the value is null...

HttpRuntime.Cache["xyz"] = Option<String>.Some("hello world");

if (HttpRuntime.Cache["xyz"].IsSome)
{
    // cache contains a non-null value for xyz...
}
于 2012-03-22T11:08:39.073 回答
0

您只需要在尝试将其添加回缓存之前检查从数据源获得的值是否不为空,请参见下文:

        Info info = null;
    if (HttpRuntime.Cache["Info_" + id.ToString() + "_" + quantity.ToString()] != null)
        info = HttpRuntime.Cache["Info_" + id.ToString() + "_" + quantity.ToString()] as Info;
    if (info == null)
    {
        info = (from dd in dc.Infos
                          where dd.id == id && dd.active == true && dd.quantitytooffset == quantity
                          select dd).SingleOrDefault();
        if (info != null)
        {
            HttpRuntime.Cache.Add("Info_" + id.ToString() + "_" + quantity.ToString(), info, null, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.High, null);
        }
    }

当您as Info在代码开头使用转换时,如果缓存中不存在密钥,它null无论如何都会返回一个值,因此您不需要将null值存储在缓存中。在缓存中存储null值实际上并没有任何用处,因此框架不允许您这样做是有原因的。

另外作为一个小提示,最好创建一次缓存密钥,然后重新使用它,而不是每次使用时都重新构建它。例如:

var key = string.Format("Info_{0}_{1}", id, quantity);

然后只需使用:

HttpRuntime.Cache[key]

访问它时,它将使您的代码不易出现拼写错误。

于 2012-03-22T11:22:22.510 回答
0

这是一个通用的静态类/方法来解决这个非常常见的问题(null 表示“我检查过但它不存在,我不需要再次检查”)。

该解决方案像其他答案一样包装该值。

使用示例

    var user = await Cached.Get(
          _cache, userName, 
          async () => _dbContext.LoadAsync<DbUser>(userName)));

执行

    public class CachedEntry<T>
    {
        public CachedEntry(T value)
        {
            Value = value;
        }

        public T Value { get; }
    }

    public static async Task<T> Get<T>(IMemoryCache cache, 
    string key, Func<Task<T>> getDelegate)
    {
        if (key == null)
        {
            throw new ArgumentNullException(nameof(key));
        }

        var cachedEntry = cache.Get<CachedEntry<T>>(key);
        if (cachedEntry == null)
        {
           var result = await getDelegate();

           cachedEntry = new CachedEntry<T>(result);
           cache.Set(key, cachedEntry);
        }

        return cachedEntry.Value;
    }

于 2019-10-14T00:31:23.530 回答