如何在EF Core中创建条件查询过滤器?

6
根据全局查询过滤器文档,我们无法为实体使用多个查询过滤器,只能使用一个具有多个条件的过滤器:

目前不支持在同一实体上定义多个查询过滤器-仅应用最后一个。但是,您可以使用逻辑AND运算符(&&在C#中)定义一个具有多个条件的单个过滤器。

因此,在我正在使用EF Core 3.1开发的项目中,我尝试这样做。在我的查询过滤器中,我尝试应用一个关于和一个关于的条件:
internal Expression<Func<TEntity, bool>> QueryFilters<TEntity>()
    where TEntity : class {
    return _ => (TenantId.HasValue
                 && _ is ITenantableEntity
                 && ((ITenantableEntity)_).TenantId == new TenantId(TenantId.Value)
                    || true)
                && (_ is IDeletableEntity
                    && !((IDeletableEntity)_).IsDeleted
                    || true);
}

TenantId 是在 DbContext 上定义的属性:

internal int? TenantId => _identity.TenantId;

我遇到的问题是在某些场景,例如Hangfire后台作业中,TenantId将始终为空。我认为在上述条件中已经对此进行了保护,但当我尝试时,生成了以下查询参数:
queryContext.AddParameter(
    name: "__ef_filter__HasValue_0",
    value: (object)Invoke(queryContext => Convert(Convert(queryContext.Context, DbContext).TenantId.HasValue, Object), queryContext)
);
queryContext.AddParameter(
    name: "__ef_filter__p_1",
    value: (object)Invoke(queryContext => Convert(Convert(new TenantId(Convert(queryContext.Context, DbContext).TenantId.Value), Nullable`1), Object), queryContext)
);

由于这些参数,查询会因NRE而崩溃。是否有更好或更合适的方法来建立查询过滤器中的表达式,以便如果 TenantId 有值,则生成参数,否则不生成而不需要使用嵌套条件语句?
要使后台作业中的查询成功,我必须使用 IgnoreQueryFilters(),这修复了 TenantId 检查,但现在也忽略了我想继续保留的 IsDeleted 检查。

你找到解决办法了吗?我遇到了同样的问题,每当它检查HasValue时,它都停留在初始化的值上,这个值是从第一次调用中设置的。 - undefined
1个回答

0
我认为你的问题不在于如何处理全局过滤器查询,而在于如何执行后台作业。
TenantId和其他依赖于已登录用户的信息将无法在hangfire作业中使用。
你可以通过将适当的参数传递给后台作业来轻松解决这个问题,这样hangfire将在运行时将其序列化到数据库中,并在运行时反序列化。
private long currentTenantId = loggedUser.GetTenantId(); // or any other way to get the tenantId when the background job was scheduled.
BackgroundJob.Enqueue<ISomeService>(s => s.SomeFunction(currentTenantId));

如果你查看hangfire的Job表,你会注意到InvocationData和Arguments列将保存运行SomeFunction()所需的所有信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接