【问题标题】:How can I cache a has-many relationship with entity 6 framework?如何缓存与实体 6 框架的多方关系?
【发布时间】:2017-08-01 15:51:33
【问题描述】:

我有一个基于 ASP.NET MVC5 框架和 Entity 6 框架编写的应用程序。

通常,缓存关系没有帮助。但是,我有一个案例,相关数据永远不会改变,但父母会改变。我正在寻找一种仅缓存关系的方法,这样我就不必在每次加载页面时都进行硬读。

我有以下两个类

public class Item 
{
    public string Id { get; set; }
    public string Name { get; set; }
    public int CategoryId { get; set; }
    public decimal Rate { get; set; }
    ...
    ...
    public virtual ICollection<ItemRecord> Records { get; set; }
}

public class ItemRecord 
{
    public string Id { get; set; }
    public string Title { get; set; }
    public decimal Description { get; set; }
    public decimal Amount { get; set; }

    [ForeignKey("Item")]
    public int ItemId { get; set; }
    ...
    ...
    public virtual ItemRecord Item { get; set; }
}

在控制器中的 Index 操作中,我可以使用以下 linq 语句获取数据。

public ActionResult Index(int? id)
{
    if(id.HasValue) 
    {
        var items = Context.Items.Where(item => item.CategoryId == id.Value)
                                 .Include(x => x.Records)
                                 .ToList();
    }
    ....
}

由于Item 模型一直在变化,我不想缓存它。但是,我想缓存 Records 关系中的所有数据,因为它永远不会改变并且它是大型数据集。

问题 如何在上面的示例中缓存 Records 关系?

我尝试使用OutputCache 属性来缓存这样的关系

public class Item 
{
    public string Id { get; set; }
    public string Name { get; set; }
    public int CategoryId { get; set; }
    public decimal Rate { get; set; }
    ...
    ...
    [OutputCache(Duration = 3600, VaryByParam = "CategoryId", Location = OutputCacheLocation.Server)]
    public virtual ICollection<ItemRecord> Records { get; set; }
}

你可以看出这不起作用,这是我得到的错误

属性“OutputCache”在此声明类型上无效。这是 仅对“类、方法”声明有效。

显然OutputCache 用于缓存类而不是实体关系。

【问题讨论】:

    标签: c# asp.net entity-framework caching asp.net-mvc-5


    【解决方案1】:

    不,OutputCache 用于缓存操作的响应。它实际上缓存了整个响应,因此不必运行操作本身。它不适合您只想缓存特定数据的场景。

    为此,您需要 MemoryCache 之类的东西或 Redis 之类的 NoSQL 解决方案。 MemoryCache 通常更易于使用,但有重要限制:

    1. 顾名思义,缓存在内存中,因此只有在保留内存时才会存在。也就是说,重新启动服务器,或者只是让 AppPool 停止,无论是作为正常回收、显式关闭或崩溃的一部分,都会擦除您缓存的所有内容。它也将受到正常内存优化的影响。例如,如果操作系统需要为另一个进程回收内存,缓存将是最先被牺牲的东西之一。

    2. 它是进程绑定的,如果您使用多个进程(网络花园),每个进程的缓存将是唯一的,这可能意味着在内存中多次包含相同的数据,每个进程一次。

    如果你想要一个更稳定的缓存,你需要使用像 Redis 这样的东西,它也是一个内存系统,由文件系统支持,也可以分布式。这意味着您可以让它在完全不同的服务器上运行,甚至可以在多个不同的服务器上运行,以实现故障转移冗余。这将有点难以实现,因为您必须实际设置 Redis 并配置与它的连接,但我在这里特别推荐 Redis,因为微软已经做了很多工作以确保它在 Windows 上都能很好地运行以及诸如 ASP.NET 应用程序之类的东西。 Redis 实际上是 Azure Cache 的后盾,因此他们有动力使其无缝化并随时掌握更新等。

    【讨论】:

    • 感谢您的帮助。是不是有一个内置库允许我使用 Redis 来缓存关系?或者这是我必须从头开始写的东西?
    • 不是内置库,但有一些客户端可用作 Nugets。我使用了 Stack Exchange 客户端 (stackexchange.github.io/StackExchange.Redis)
    • 这很棒。我只是想在开始使用该软件包之前了解工作流程。我将如何使用这个包来缓存关系的结果?
    • 您很可能希望将其与 StackExchange.Redis.Extensions (github.com/imperugo/StackExchange.Redis.Extensions) 结合使用,后者具有更多类似于 MemoryCache 的 API 并支持诸如序列化之类的东西,允许您例如,将整个对象添加为 JSON 字符串,然后将它们反序列化为对象。
    • 自从您发布此答案以来,我一直在围绕您的建议研究解决方案。我试图弄清楚如何在实体框架中缓存关系,但是......没有运气。这个博客“下面的链接”解释了如何使用RedisICacheProviderRedis 服务器交互。但我不确定如何使用它来缓存问题中列出的Records 关系。我是否需要使用延迟加载来完成此操作?我希望继续使用 Eager 加载来完成工作。 blog.chudinov.net/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多