Null as value in HttpRuntime.Cache.Add

独自空忆成欢 提交于 2019-12-23 10:57:32

问题


I want to store null for some of the keys in HttpRuntime.Cache as I dont want to again go to Database to find that there is no entry for that key.

So first time, it goes to database and fills the cache. The intent is to serve the following calls using cached data instead of doing the database call.

Here is the code that I am using the following:

            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);
        }

The last line of code i.e. HttpRuntime.Cache.Add throws an System.ArgumentNullException: Value cannot be null.

Any idea if this is possible or I need to use other datastructure to store null values and look up later?


回答1:


You could use your own "null" value to place into cache. For example,

private static Info NULL_INFO = new Info();

Then you could use that instead of null in HttpRuntime.Cache.Add and later after retrieval from cache check that you didn't get your 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



回答2:


I wrote a blog post recently about how the null keyword is often abused leading to this kind of confusion. In your particular case I would look at using an option type to indicate the lack or presence of data rather than null.

I have a simple implementation of an Option type you can use here

The usage would then be something like:

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...
}



回答3:


You just need to check whether the value obtained from your data source is not null before trying to add it back to the cache, see below:

        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 you are using the as Info conversion at the beginning of your code, if the key isn't present in the cache it'll return a null value anyway, so you don't need to store the null value in cache. Storing null values in the cache doesn't really serve any use, so there's a reason the framework is not allowing you to do that.

Also as a slight side-note, it would be good to create your cache key once, then re-use it rather than reconstructing it every time it's used. For instance:

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

Then just use:

HttpRuntime.Cache[key]

When accessing it, it'll make your code less prone to typo errors.




回答4:


This is a generic static class/method to solve this quite common problem (null which means "i checked and it doesn't exist, I don't need to check again").

This solution wraps the value like in the other answers.

Usage example

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

Implementation

    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;
    }



来源:https://stackoverflow.com/questions/9820629/null-as-value-in-httpruntime-cache-add

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!