首页 > 解决方案 > 使用带有大量 Include() 的 EF Core 时如何正确缓存查询结果?

问题描述

我正在使用https://github.com/VahidN/EFCoreSecondLevelCacheInterceptor包在我的 ASP.NET Core 应用程序中缓存 EF Core 查询结果。根据创作者的说法,它是这样工作的:

EF 命令的结果将存储在缓存中,因此相同的 EF 命令将从缓存中检索其数据,而不是再次针对数据库执行它们。

因此,如果生成的 SQL 相同,此库将返回缓存结果。

问题是我在查询数据库时使用了很多 Include() 方法。这是必需的,因为某些页面显示了存储在不同相关数据库表中的大量信息。此外,查询包含当前用户特定的信息,例如当前用户是否喜欢该帖子。正如我所听到的那样缓存用户特定的信息是不正确的,并且会导致冗余缓存条目,因为唯一正在更改的数据是当前用户 ID。

查询示例:

var post = dbContext.Posts
   .Where(p => p.Id == 1)
   .Include(p => p.Comments)
   .Include(p => p.VoteTracker
               .Where(t => t.UserId == "{current user ID}"))
   // ... other Include(...) calls
   .ToList();

生成的 SQL 可能非常庞大,有很多 JOIN。所以这里缓存的问题是:

  1. 如果评论被更改,那么上面的整个查询也将失效,因为这个库

使用其拦截器监视所有 CRUD 操作,然后自动使相关的缓存条目无效

  1. 在查询中包含当前用户特定信息会创建许多相同的缓存条目,这些条目仅因当前用户特定信息而异

在这里缓存的更好方法是什么?

首先想到的是拥有可以缓存的单独查询。例如:

// Post and Comments query will be cached
var post = dbContext.Posts.SingleOrDefault(p => p.Id == 1);

var comments = dbContext.Comments
    .Where(c => c.PostId == 1)
    .ToList();

// This one will be excluded from caching (because of user-specific info)
var voteTracker = dbContext.VoteTrackers
    .SingleOrDefault(t => t.PostId == 1 && t.UserId == "{current user ID}");

这是一个好方法吗?如果不是哪个更好?

我为此苦苦挣扎,但很难找到正确的解决方案。非常感谢您!:)

标签: c#cachingentity-framework-core

解决方案


推荐阅读