使用运行时数据在 EF Core fds 中的 HasQueryFilter() 中过滤行

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

在我的应用程序中,有一个名为

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

RecordType
是:

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

当用户以

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);
c# entity-framework-core ef-code-first
2个回答
2
投票

我想使用

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

实际上这是可能的,但记录很少 - 只是作为全局查询过滤器文档主题示例的提示:

注意

DbContext
实例级别字段的使用:
_tenantId
用于设置当前租户。模型级过滤器将使用来自正确上下文实例(即正在执行查询的实例)的值。

它的真正含义和应该记录的是,不是来自参数或不是常量的全局过滤器查询表达式部分必须在上下文类中“扎根”才能保持动态。或者换句话说,必须源自上下文类的属性/字段/方法。 例如,如果您的上下文有属性

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

然后您可以在全局查询过滤器中使用,它将针对每个上下文动态评估。您可以在上下文类中使用类似的内容来一般设置它

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 }); } } }



0
投票

MyDbContext myDbContext = null!; builder.HasQueryFilter(e => e.Foo == myDbContext.Bar);

由于 
HasQueryFilter

接受表达式,因此

myDbContext
的定义时值 (null) 将不会被捕获,它将被 EF 替换为正在执行查询的 DbContext 实例。
此方法使您能够在 DbContext 词法范围之外和/或在静态方法中定义查询过滤器,例如,如果您使用自己的实体构建器并保持实际的 DbContext 干净,这非常有用。

© www.soinside.com 2019 - 2024. All rights reserved.