实体框架灵活缓存

本文关键字:缓存 框架 实体 | 更新日期: 2023-09-27 17:58:10

我正在寻找一个能与Entity Framework 6+一起工作的缓存系统。要么找到一个合适的库,要么自己实现。

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

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

EFSecondLevelCachehttps://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:我意识到缓存不起作用,但它仍然会创建到数据库的连接,因为我创建了一个新的上下文实例。但是有一个问题!我在网络服务中处理EF请求。根据web服务的主机名host:-header,将查询不同的数据库。EF Plus似乎无法处理此问题,因此如果我使用http://host1/ClientConfig我后来从http://host2/ClientConfig.有没有办法用主机名标记缓存

实体框架灵活缓存

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

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

Wiki:EF+查询缓存

示例

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。您不需要指定任何内容,它已经处理了所有内容。

其他一些功能,如Query Future,还不能在所有提供者上运行。它适用于SQL Server、SQL Azure和MySQL等流行的提供商。

您可以在每个功能下面看到需求部分。如果它支持所有提供商,我们通常会说"All supported"。

编辑:回答子问题

我在MyEF6Entitys构造函数中更改了数据库,所以问题是如果EF+将考虑数据库名称,或者这可能会造成混乱向上缓存?

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

密钥由以下部分组成:

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

有没有办法用主机名标记缓存

您可以使用缓存标签:EF+查询缓存标签&过期标签

示例:

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

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

编辑:回答子问题

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

你能生成缓存密钥并检查是否包括连接字符串吗?

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

如果我这样做(例如var clientHost),它就会起作用=数据库。客户端配置。FromCache(DateTime.Now.AddMinutes(60),hostName)。ToList();但我不应该这么做,因为connectionString不同,对吧?

是的,你是对的。如果连接字符串随主机而更改,则不需要它。