Entity Framework flexible cache

c# caching database entity-framework entity-framework-6

Question

I am looking for a cache system that works with Entity Framework 6+. Either to find a suitable library or implement it myself.

I have already investigated these two open source cache providers:

Second Level Cache for Entity Framework 6.1 https://efcache.codeplex.com/

EFSecondLevelCache https://github.com/VahidN/EFSecondLevelCache/

They seem like solid products although I am looking for a way to specify the maximum cache time within the query. I think that would be the best way to specify the oldest data I would be able to accept (since this is very dependent on business logic of course)

This would be the best way to call it I think:

using (var db = new MyEF6Entities()) {
    var path = db.Configuration.Where(c => c.name="Path")
                               .AllowFromCache(TimeSpan.FromMinutes(60));

    var onlineUserList = db.Users.Where(u => u.IsOnline)
                                 .AllowFromCache(TimeSpan.FromSeconds(30));
}

Is there a way to make an API like this?

EDIT: I have now tried EF+ as suggested by @JonathanMagnan but as an example the below code does not ever get a cache hit. I know this because it is very slow, I also see in the mysql administrator that there is a connection made with the specific query, and if I change data in the database it will show immediately, I would expect a delay of 60 minutes

public String GetClientConfig(string host, Guid deviceId) {
    using (var db = new DbEntities(host)) {
        var clientConfig = db.ClientConfig.FromCache(DateTime.Now.AddMinutes(60)).ToList();
        return string.Join("\n", clientConfig.Select(b => b.Name + "=" + b.Value));
    }
    return null;
}

EDIT 2: I realized not that caching works, however it still creates a connection to the database because I create a new context instance. There is however a problem! I do EF requests in a web service. Depending on the host name of the web service Host:-header different databases are queried. EF Plus does not seem to handle this so if I use http://host1/ClientConfig I later get the same and incorrect results from http://host2/ClientConfig. Is there a way to tag the cache with the host name?

1
1
7/31/2016 11:43:39 AM

Accepted Answer

Disclaimer: I'm the owner of the project Entity Framework Plus (EF+)

I cannot speak for other libraries you already investigated, but EF+ Query Cache allows to cache data for a specific amount of time.

Wiki: EF+ Query Cache

Example

using (var db = new MyEF6Entities()) {
    var path = db.Configuration.Where(c => c.name="Path")
                               .FromCache(DateTime.Now.AddMinutes(60));

    var onlineUserList = db.Users.Where(u => u.IsOnline)
                                 .FromCache(DateTime.Now.AddSeconds(30));
}

You can also use cache "tags" to cache your data multiple times if some logic requires data live, and other logic doesn't need it.

Example

using (var db = new MyEF6Entities()) {
    var recentUserList = db.Users.Where(u => u.IsOnline)
                                 .FromCache(DateTime.Now.AddHours(1), "recent");

    var onlineUserList = db.Users.Where(u => u.IsOnline)
                                 .FromCache(DateTime.Now.AddSeconds(30), "online");
}

From my knowledge, I don't think any cache support is taking data cached in the last X seconds.

EDIT: Answer subquestion

Thanks Jonathan. How does EF+ work with using different databases for example, and different logged in users for example. Will it handle this automatically or do I need to give it some hints ?

It depends on each feature. For example, Query Cache works with all databases provider since only LINQ is used under the hood. You don't need to specify anything, it already handles everything.

Some other features like Query Future don't work yet on all providers. It works on popular providers like SQL Server, SQL Azure, and MySQL.

You can see the requirements section under each feature. We normally say "All supported" if it supports all providers.

EDIT: Answer subquestion

I change the database in the MyEF6Entities constructor so question is if EF+ will take the database name into account or if this could mess up the cache?

Starting from v1.3.34, the connection string is now part of the key. So that will support this scenario.

The key is composed of:

  • A cache prefix
  • The connection string
  • All cache tags
  • All parameter names & values

Is there a way to tag the cache with the host name

You can use Cache Tags: EF+ Query Cache Tag & ExpireTag

Example:

var host1 = "http://host1/ClientConfig";
var host2 = "http://host2/ClientConfig";

var clientHost1 = db.ClientConfig.FromCache(DateTime.Now.AddMinutes(60), host1).ToList();
var clientHost1 = db.ClientConfig.FromCache(DateTime.Now.AddMinutes(60), host2).ToList();

All tags are part of the cache key so both queries will be cached in a different cache entry.

EDIT: Answer subquestion

I set the ConnectionString in the MyEF6Entities() constructor and it still seem to confuse data from different databases

Can you generate the cache key and check if the connection string is included?

var query = b.Users.Where(u => u.IsOnline);
var cacheKey = QueryCacheManager.GetCacheKey(query, new string[0]);

It works if I do for example var clientHost = db.ClientConfig.FromCache(DateTime.Now.AddMinutes(60), hostName).ToList(); but I shouldnt need to to this since the connectionStrings are different, right ?

Yes, you are right. You shouldn't need it if the connection string changes with the host.

2
8/22/2018 10:42:18 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow