Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reset Cache for Dapper

Is there a way to reset the cache that Dapper generates? I dropped a table column in my database, and I got the error "column not found." I reset IIS and it worked fine after that.

Can this be reset without restarting IIS? Thanks.

like image 830
SaltProgrammer Avatar asked Mar 08 '12 02:03

SaltProgrammer


2 Answers

Update 2018-02-08

The Dapper code has changed quite a bit since this answer was written almost 5 years ago. As Marc Gravell commented on the question, this shouldn't have been needed when the question was asked so it likely wouldn't be of much use today either.

The code may or may not work anymore. Even if it does still work, it's not optimal so I couldn't recommend it in good faith. Use at your own risk.


Line 227 of Database.cs shows:

static ConcurrentDictionary<Type, string> tableNameMap = new ConcurrentDictionary<Type, string>();
static ConcurrentDictionary<Type, List<string>> paramNameCache = new ConcurrentDictionary<Type, List<string>>();

which means it is private. I'm not even sure you'd be able to access it with Reflection (it'd be worth a shot though). Your best bet would be to add a ClearCache method to the source (since it is open source) and submit it for review.

Maybe Sam Saffron or Marc Gravell can elaborate.


I don't use Dapper, but I think the following extension method should work with the version in Repo:

public static class DapperExtensions
{
    public static void ClearTableCache<TDatabase>(this Database<TDatabase> dapperDb)
    {
        var fld = dapperDb.GetType().GetField("tableNameMap", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
        if (fld == null)
            throw new NotSupportedException("Unable to locate Private field tableNameMap");

        var obj = fld.GetValue(null);
        if (obj == null)
            throw new NotSupportedException("Unable to get value from tableNameMap");

        var clear = obj.GetType().GetMethod("Clear");
        if (clear == null)
            throw new NotSupportedException("Unable to locate ConcurrentDictionary<T, U>.Clear");

        clear.Invoke(obj, null);
    }
    public static void ClearParamCache<TDatabase>(this Database<TDatabase> dapperDb)
    {
        var fld = dapperDb.GetType().GetField("paramNameCache", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
        if (fld == null)
            throw new NotSupportedException("Unable to locate Private field paramNameMap");

        var obj = fld.GetValue(null);
        if (obj == null)
            throw new NotSupportedException("Unable to get value from paramNameMap");

        var clear = obj.GetType().GetMethod("Clear");
        if (clear == null)
            throw new NotSupportedException("Unable to locate ConcurrentDictionary<T, U>.Clear");

        clear.Invoke(obj, null);
    }
}

It hasn't been tested with Dapper but I tested out the principle using POCO's. Accessing private API's is dangerous (at best) but the reflection used in this code sample should work with the current version.

like image 178
M.Babcock Avatar answered Oct 19 '22 17:10

M.Babcock


There is now SqlMapper.PurgeQueryCache() which clears reflection cache and query cache.

like image 1
Alex from Jitbit Avatar answered Oct 19 '22 17:10

Alex from Jitbit