编写一个在 DbContext 重新创建之间重新评估的 LambdaExpression?



我正在尝试使用 EF Core 3.0 中的全局查询筛选器。总的来说,它们工作得很好,但有一个小问题。我一直在尝试以类似于此处指南的方式设置多租户。我的用例有点不同,因为租户派生自查询字符串参数(或标头(,并且请求之间可能会发生变化。

如果我定义一个接口IOrganizationEntity与一个名为Organization的成员.我能够使用语句entity.HasQueryFilter<IOrganizationEntity>(o => o.Organization == OrganizationId)定义全局查询过滤器,这按预期工作。但是,我试图避免在我的实体 POCO 上放置Organization属性,而是尝试使用类似于以下内容的内容:

private Guid OrganizationId => HasOrganization ? _organizationService.GetCurrentOrganizationId() : Guid.Empty;
private void ConfigureOrganizationFilter(ModelBuilder modelBuilder)
{
foreach (var entity in modelBuilder.Model.GetEntityTypes().Where(x =>
typeof(IOrganizationEntity).IsAssignableFrom(x.ClrType)))
{
entity.AddProperty(nameof(Organization), typeof(Guid));
// Note, AddQueryFilter is an extension method that allows us to add multiple
// query filters to a single type of entity.
entity.AddQueryFilter(IsOrganizationRestricted(entity.ClrType));
}
}
private LambdaExpression IsOrganizationRestricted(Type type)
{
var propertyMethod = typeof(EF).GetMethod(nameof(EF.Property),
BindingFlags.Static |
BindingFlags.Public)?.MakeGenericMethod(typeof(Guid));
if (propertyMethod == null)
throw new ArgumentException("Object does not appear to be valid for operation.");
var param = Expression.Parameter(type, "it");
var prop = Expression.Call(propertyMethod, param, Expression.Constant(nameof(Organization)));
var condition = Expression.MakeBinary(ExpressionType.Equal, prop, Expression.Constant(OrganizationId));
var lambda = Expression.Lambda(condition, param);
return lambda;
}

但是,当我使用上面的代码时,过滤在第一次运行时按预期工作,但在OrganizationId已更改的后续运行中失败。我对显式编写Expression函数相当陌生,所以我不确定需要发生什么来强制重新评估 OrganizationId

为了重新计算,过滤器表达式必须访问数据库上下文派生类的属性/字段/方法。

假设有问题的代码位于数据库上下文派生类中,即OrganizationId是该类的属性,问题是

Expression.Constant(OrganizationId)

在生成筛选器时对其进行计算,并将常量值绑定到筛选器表达式中。

相反,您应该绑定OrganizationId属性访问器表达式(即Expression.Property( 像这样:

// this.OrganizationId
Expression.Property(Expression.Constant(this), nameof(OrganizationId)) 

最新更新