【发布时间】:2018-08-23 21:00:59
【问题描述】:
我有一个多租户 ASP.NET 应用程序,我们的数据库设置了软删除。最初,我们直接在查询级别处理数据的限制,例如:
var foos = context.Foos.Where(foo => !foo.Deleted && foo.TenantId = currentTenantId).ToList();
正如您可以想象的那样,这会使我们的数据访问层中的所有查询膨胀,并且如果忘记添加正确的过滤条件,会使 API 非常容易受到攻击。我们决定使用Z.EntityFramework.Plus.EF6 对上下文应用全局过滤:
public class FooDataContextFactory
{
public FooDataContext CreateContext()
{
var context = new FooDataContext();
context.Filter<Foo>(collection => collection.Where(foo=> !foo.Deleted));
var principal = Thread.CurrentPrincipal as ClaimsPrincipal;
if (principal.HasClaim(claim => claim.Type == "TenantId"))
{
var currentTenantId = int.Parse(principal.FindFirst("TenantId").Value);
context.Filter<Foo>(collection => collection.Where(foo => foo.TenantId == currentTenantId));
}
return context;
}
}
这非常适合单个用户。但是,当您切换租户时,我们会遇到将过滤器表达式保存在 the query plan cache 中的问题。这是带有 Entity Framework Plus 的known issue,由于它似乎没有得到解决,我需要找到一种解决方法。
我能想到的最直接的解决方案是将查询计划缓存的生命周期与当前会话相关联,当用户注销或切换租户时,缓存被销毁。这可能吗?如果可以,我该如何实现?
【问题讨论】:
-
我怀疑这是可能的。
-
按照您的建议,only 方法可以做到这一点......我的意思是有很多更好的方法可以做到这一点而不必担心缓存......就是创建您的上下文在另一个应用程序域中。 EF QueryCache 存储在 AppDomain 级别,因此丢弃 AppDomain 会丢弃缓存。话虽如此,由于查询计划被缓存,您遇到了什么实际问题?
-
我认为这个问题很清楚地说明了它 - 查询计划被缓存了,它包括类似于
WHERE TenantId = 3的内容。该值未参数化,因此当我更改租户时,查询不会返回正确的结果 -
Jonathan 在链接问题中很好地总结了这个问题 - “真正的问题是计划在调用拦截器之前与表达式一起缓存。这意味着两个上下文具有不同的过滤器但具有相同的查询将使用相同的执行计划,这是非常糟糕的,因为不需要应用相同的过滤器。”
标签: c# asp.net-mvc-4 entity-framework-6 entity-framework-plus