在 EF Core fds 中使用 Runtime Data 过滤 HasQueryFilter() 中的行

Use Runtime Data to filter Rows in HasQueryFilter() in EF Core fds

在我的应用程序中有一个名为 RecordType 的枚举,所有表都包含一个名为 'TypeId' 的字段。 当用户添加一条新记录时,我根据用户的TypeId设置TypeId。通过这种方式,我想加载与每个用户类型相关的数据。

RecordType 是:

public enum RecordType
{
    None=0,
    
    Programmers = 1,
    
    Marketer = 3,
    
    Financial = 5,
}

当用户以 Programmer 类型登录系统时,我必须只加载类型为 'Programmer' 的用户添加的所有数据。

我想使用 HasQueryFilter(),但据我所知,它只能用于静态字段,不能使用 currentUserId,因为在 运行 应用程序之后是可能的。

我添加了这样的扩展方法:

public static class QueryFilterExtensions
{
    public static IQueryable<TEntity> FilterByUser<TEntity>(this IQueryable<TEntity> query, ICurrentUserService currentUser) where TEntity : BaseEntity
    {
        if (currentUser.TypeId != Domain.Enums.RecordType.None)
            query = query.Where(e => e.TypeId == currentUser.TypeId);
        return query;
    }
}

以这种方式,我必须在阅读的所有部分中重新调用此扩展方法,如下所示。

 return await _dbContext.Groups.OrderBy(x => x.Id)
             .FilterByUser(_currentUser)
                    .ProjectTo<GroupDto>(_mapper.ConfigurationProvider)
                    .PaginatedListAsync(request.PageIndex, request.PageSize);

I wanted to use HasQueryFilter() but As I know it just work with static fields and can not use currentUserId beacuse it is possible after running application.

实际上这是可能的,但文档很少 - 就像 Global Query Filters 文档主题示例的提示:

Note the use of a DbContext instance level field: _tenantId used to set the current tenant. Model-level filters will use the value from the correct context instance (that is, the instance that is executing the query).

它的真正含义和应该记录在案的是,不是来自参数或不是常量的全局过滤器查询表达式部分必须 rooted 在上下文 class为了动态。或者换句话说,必须源自上下文 class.

的 property/field/method

例如,如果您的上下文有 属性

public RecordType CurrentUserTypeId => // coming from injected service or something

然后您可以在全局查询过滤器中使用,它将针对每个上下文进行动态评估。您可以在您的上下文 class

中使用类似的内容进行一般设置

void SetQueryFilter<TEntity>(ModelBuilder modelBuilder)
    where TEntity : BaseEntity
{
    modelBuilder.Entity<TEntity>().HasQueryFilter(
        e => this.CurrentUserTypeId == RecordType.None || e.TypeId == this.CurrentUserTypeId);
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
    // other stuff...
    var setQueryFilterMethod = new Action<ModelBuilder>(SetQueryFilter<MyBaseEntity>)
        .Method.GetGenericMethodDefinition();
    foreach (var entityType in modelBuilder.Model.GetEntityTypes())
    {
        if (entityType.BaseType == null && typeof(BaseEntity).IsAssignableFrom(entityType.ClrType))
        {
            setQueryFilterMethod
                .MakeGenericMethod(entityType.ClrType)
                .Invoke(this, new object[] { modelBuilder });
        }
    }
}