条件租赁全局过滤以及 EF 中的运行时评估

问题描述 投票:0回答:1

我正在尝试构建一个 DbContext 基类,它自动实现对租户感知、审计日志等的支持,以便我的团队可以继承它,添加他们的实体,并且只需很少的手动工作,就可以拥有一个可操作的租户强制和托管数据库上下文。这是为了减少改造中的工作量和定制程度,使其稍微不那么疯狂(我们有大约 30 多个服务,每个服务都有自己的数据库上下文)。

我有一个类似这样的界面

ITenantAwareEntity

public interface ITenantAwareEntity
{
    /// <summary>
    /// Specifies the customer that this record belongs to.
    /// </summary>
    Guid? CustomerId { get; set; }
}

我构建了一个

SaveChangesInterceptor
,以确保在使用注入的
CustomerId
保存之前始终填充
IContextProvider
,该注入提供当前 DbContext 信息,例如当前用户、当前客户等。

在查询方面,我尝试使用全局过滤器强制租赁,该过滤器使用前面提到的

CustomerId
添加了
IContextProvider
的过滤器。有很多关于如何做到这一点的例子,但它们看起来都与我的实现有很大不同,我正在绞尽脑汁地思考如何使这项工作发挥作用。 Lambda 表达式显然是我的克星。

我注入 DbContext 的上下文提供程序(并公开为受保护的 get/私有设置属性)有一个名为

IsServiceContext
的属性,它指示使用 DbContext 的身份不属于特定租户,而是一个我不想应用全局过滤器的服务帐户,因为它可能一次管理多个租户的记录。

我完全不知道如何编写一个 lambda 表达式,其基本内容如下:

  • 如果请求用户是
    IContextProvider
    中定义的服务帐户,则不应用过滤器。
  • 否则,过滤
    CustomerId
    IContextProvider
    属性要求的任何结果集。

我如何编写它,以便我可以将其应用于实现

ITenantAwareEntity
的所有实体,并在运行时为每个数据库操作动态评估它?

c# entity-framework lambda
1个回答
0
投票

EF Core 允许在查询过滤器中仅使用 DbContext 的属性。所以定义它们:

public class MyDbContext : DbConext
{
    ...

    protected bool IsServiceUser => _contextProvider.IsServiceUser;
    protected Guid? CustomerId   => _contextProvider.CustomerId;

    ...
}

无法动态更改查询过滤器 - 它是在模型中定义的,以后无法更改。将

IsServiceUser
CustomerId
组合在一个过滤器中:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    ... // configuring classes

    modelBuilder.Entity<Some>(e => IsServiceUser || CustomerId == e.CustomerId);
}    

您还可以使用以下自定义扩展 ApplyQueryFilter 为所有实体定义查询过滤器:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    ... // configuring classes

    modelBuilder.ApplyQueryFilter<ITenantAwareEntity>(e => IsServiceUser || CustomerId == e.CustomerId);
}    
© www.soinside.com 2019 - 2024. All rights reserved.