实体框架灵活缓存

时间:2016-07-22 13:06:52

标签: c# database entity-framework caching entity-framework-6

我正在寻找与Entity Framework 6+兼容的缓存系统。要么找到合适的图书馆,要么自己实施。

我已经调查了这两个开源缓存提供程序:

实体框架6.1的二级缓存 https://efcache.codeplex.com/

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

它们看起来像固态产品,虽然我正在寻找一种方法来指定查询中的最大缓存时间。我认为这将是指定我能够接受的最旧数据的最佳方式(因为这当然非常依赖于业务逻辑)

这是我认为最好的称呼方式:

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

有没有办法制作这样的API?

  

编辑:我现在已经按照@JonathanMagnan的建议尝试了EF +,但作为一个例子,下面的代码并没有得到缓存命中。我知道这是因为它很慢,我也在mysql管理员看到有一个与特定查询的连接,如果我更改数据库中的数据它会立即显示,我预计会延迟60分钟

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

编辑2:我意识到缓存不起作用,但它仍然创建了与数据库的连接,因为我创建了一个新的上下文实例。但是有一个问题!我在Web服务中执行EF请求。根据Web服务主机的主机名:-header查询不同的数据库。 EF Plus似乎没有处理这个,所以如果我使用http://host1/ClientConfig我后来得到http://host2/ClientConfig相同且不正确的结果。有没有办法用主机名标记缓存?

1 个答案:

答案 0 :(得分:2)

免责声明:我是该项目的所有者Entity Framework Plus (EF+)

我不能代表您已调查过的其他库,但EF +查询缓存允许在特定时间内缓存数据。

维基:EF+ Query Cache

实施例

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

如果某些逻辑需要实时数据,您也可以使用缓存“标记”多次缓存数据,而其他逻辑则不需要数据。

实施例

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

据我所知,我认为任何缓存支持都不会在最后X秒内缓存数据。

编辑:回答子问题

  

谢谢乔纳森。 EF +如何使用不同的数据库   例如,以及不同的登录用户。它会处理吗   这是自动还是我需要给它一些提示?

这取决于每个功能。例如,查询缓存适用于所有数据库提供程序,因为只有LINQ才能使用。您不需要指定任何内容,它已经处理了所有内容。

“查询未来”等其他一些功能尚未在所有提供商上运行。它适用于SQL Server,SQL Azure和MySQL等流行的提供程序。

您可以在每个功能下看到要求部分。如果支持所有提供商,我们通常会说“全部支持”。

编辑:回答子问题

  

我在MyEF6Entities构造函数中更改数据库,所以问题是   如果EF +将考虑数据库名称或如果这可能会弄乱   缓存?

从v1.3.34开始,连接字符串现在是密钥的一部分。所以这将支持这种情况。

密钥由:

组成
  • 缓存前缀
  • 连接字符串
  • 所有缓存标记
  • 所有参数名称&值
  

有没有办法用主机名

标记缓存

您可以使用缓存标记:EF+ Query Cache Tag & ExpireTag

示例:

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

所有标记都是缓存键的一部分,因此两个查询都将缓存在不同的缓存条目中。

编辑:回答子问题

  

我在MyEF6Entities()构造函数中设置了ConnectionString   仍然似乎混淆了来自不同数据库的数据

您是否可以生成缓存密钥并检查是否包含连接字符串?

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

如果我做例如var clientHost =,它可以工作   db.ClientConfig.FromCache(DateTime.Now.AddMinutes(60),   主机名).ToList();但是我不需要这样做   connectionStrings是不同的,对吧?

是的,你是对的。如果连接字符串随主机一起变化,则不应该需要它。