Search code examples
c#cachingdapper

What exactly is the "information" that dapper caches?


On Dapper's documentation found here it states:

Limitations and caveats

Dapper caches information about every query it runs, this allow it to materialize objects quickly and process parameters quickly. The current implementation caches this information in a ConcurrentDictionary object.

What exactly does this mean? Ex: Is it caching returned data, or the query itself, or bits of both?

It also says that "this [cached] data is never flushed". How does this effect the "cached information" if the design schema of the table(s) you are querying is changed?


Solution

  • As far as I know has each query you issue an Identity, depending on the sql query, its command type and its parameters. The cache is a dictionary with concurrent access.

    Dictionary<Identity, CacheInfo> _queryCache
    

    This CacheInfo object contains the IDataReader and IDBCommand functions and some control counters which limit the cached amount.

    Since no server-side (database schema etc.) are cached, it actually doesn't have any influence.

    Edit: Thats how the Identity class looks like used for caching.

    private Identity(string sql, CommandType? commandType, string connectionString, Type type, Type parametersType, Type[] otherTypes, int gridIndex)
            {
                this.sql = sql;
                this.commandType = commandType;
                this.connectionString = connectionString;
                this.type = type;
                this.parametersType = parametersType;
                this.gridIndex = gridIndex;
                unchecked
                {
                    hashCode = 17; // we *know* we are using this in a dictionary, so pre-compute this
                    hashCode = hashCode * 23 + commandType.GetHashCode();
                    hashCode = hashCode * 23 + gridIndex.GetHashCode();
                    hashCode = hashCode * 23 + (sql == null ? 0 : sql.GetHashCode());
                    hashCode = hashCode * 23 + (type == null ? 0 : type.GetHashCode());
                    if (otherTypes != null)
                    {
                        foreach (var t in otherTypes)
                        {
                            hashCode = hashCode * 23 + (t == null ? 0 : t.GetHashCode());
                        }
                    }
                    hashCode = hashCode * 23 + (connectionString == null ? 0 : connectionString.GetHashCode());
                    hashCode = hashCode * 23 + (parametersType == null ? 0 : parametersType.GetHashCode());
                }
            }
    

    And here's the CacheInfo

    class CacheInfo
    
            {
                public Func<IDataReader, object> Deserializer { get; set; }
                public Func<IDataReader, object>[] OtherDeserializers { get; set; }
                public Action<IDbCommand, object> ParamReader { get; set; }
                private int hitCount;
                public int GetHitCount() { return Interlocked.CompareExchange(ref hitCount, 0, 0); }
                public void RecordHit() { Interlocked.Increment(ref hitCount); }
            }
    

    And finally the container of the cache.

    static readonly System.Collections.Concurrent.ConcurrentDictionary<Identity, CacheInfo> _queryCache = new System.Collections.Concurrent.ConcurrentDictionary<Identity, CacheInfo>();
    

    Have a look at the source code, its very well written and easy to follow / debug. Just drag the file into your project.