【问题标题】:Write a LambdaExpression that is reevaluated between DbContext recreations?编写一个在 DbContext 重新评估之间重新评估的 LambdaExpression?
【发布时间】:2019-11-27 22:48:25
【问题描述】:

我正在尝试在 EF Core 3.0 中使用 Global Query Filters。总的来说,他们工作得相当好,但有一个小问题。我一直在尝试以类似于指南here 的方式设置多租户。我的用例有点不同,因为租户是从查询字符串参数(或标头)派生的,并且在请求之间会发生变化。

如果我使用名为Organization 的成员定义接口IOrganizationEntity。我可以使用语句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

【问题讨论】:

  • 写出如果手动完成表达式会是什么样子,并将其用作模板来动态构建表达式。

标签: c# entity-framework lambda entity-framework-core


【解决方案1】:

为了重新评估,过滤器表达式必须访问 db 上下文派生类的属性/字段/方法。

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

Expression.Constant(OrganizationId)

在您构建过滤器时对其进行评估,并将 constant 值绑定到过滤器表达式中。

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

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

【讨论】:

    猜你喜欢
    • 2020-08-19
    • 2019-06-23
    • 1970-01-01
    • 1970-01-01
    • 2015-04-04
    • 2010-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多