繁体   English   中英

扩展方法中的表达式树将在本地评估

[英]Expression Tree in extension method will be evaluated locally

我想将TenantId添加到Asp.Net Identity表(例如:User)。

以下代码片段可以正常工作。 租户上下文将通过DI注入,并且租户将根据http上下文域进行更改:

private readonly ITenantContext<ApplicationTenant> tenantContext;

public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, ITenantContext<ApplicationTenant> tenantContext) : base(options)
{
    this.tenantContext = tenantContext;
}

protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);

    builder.Entity<ApplicationUser>(b =>
    {
        // add tenant
        b.Property(typeof(int), "TenantId");
        b.HasQueryFilter(x => EF.Property<int>(x, "TenantId") == this.tenantContext.Tenant.Id);
    });
}

为了重用,我想为entityBuilder创建一个扩展方法:

public static class EntityTypeBuilderExtensions
{

    public static void AddTenancy<TEntity>(
        this EntityTypeBuilder<TEntity> builder,
        Expression<Func<int>> tenantId,
        string propertyName = "TenantId")
        where TEntity : class
    {
        // validate
        Ensure.Argument.NotNull("builder", builder);

        // add property to entity
        builder.Property(typeof(int), propertyName).IsRequired();


        /* THIS WORKS BUT WILL BE EVALUATED LOCALLY */
        // left
        var parameterExp = Expression.Parameter(typeof(TEntity), "x"); // e = TEntity => e.g: User
        var propertyNameExp = Expression.Constant(propertyName, typeof(string)); // the name of the tenant column - eg.: TenantId
        // right
        var tTenantId = Expression.Convert(tenantId.Body, typeof(int));  // tenantId
        var propertyMethod = typeof(EF).GetMethod(nameof(EF.Property), BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(typeof(int)); // build EF.Property
        var propertyMethodExec = Expression.Call(propertyMethod, parameterExp, propertyNameExp);  // represents EF.Property(e, "TenantId")
        var bodyExp = Expression.Equal(propertyMethodExec, tTenantId);
        var lambda = Expression.Lambda(bodyExp, parameterExp);
        builder.HasQueryFilter(lambda);
    }
}

并在数据库上下文中:

private Func<int> tenantId => () =>
{
    // return tenant id
    if (this.tenantContext != null && this.tenantContext.Tenant != null)
    {
        return this.tenantContext.Tenant.Id;
    }

    return -1;
};

protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);

    builder.Entity<ApplicationUser>(b =>
    {
        b.AddTenancy(() => this.tenantId(), "TenantId");
    });
}

扩展方法也可以,但是表达式是在本地求值的:-(。有人可以帮我修复它吗?

LINQ表达式'where(Property([x],“ TenantId”)== Invoke(__ ef_filter__tenantId_0))'无法翻译,将在本地进行评估。 LINQ表达式'where([x] .NormalizedUserName == __normalizedUserName_0)'无法翻译,将在本地进行评估。 LINQ表达式“ FirstOrDefault()”无法翻译,将在本地进行评估。

问题是这里的Func

private Func<int> tenantId => ...

这会导致翻译Invoke(__ef_filter__tenantId_0))和客户评估错误。

解决方案是使tenantId简单int返回属性或方法。 例如,保持通话

b.AddTenancy(() => this.tenantId(), "TenantId");

它应该更改为

private int tenantId()
{
    // return tenant id
    if (this.tenantContext != null && this.tenantContext.Tenant != null)
    {
        return this.tenantContext.Tenant.Id;
    }

    return -1;
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM