【问题标题】:Analyse the tables involved in an IQueryable分析 IQueryable 中涉及的表
【发布时间】:2022-08-10 17:17:11
【问题描述】:

我有一个要求,我需要查看将由 EF Core 通过 IQueryable 运行的查询中涉及的所有表

有没有人能够做到这一点?

让我们用一个例子

var cars = await (from car in DbContext.Cars
    from salesperson in DbContext.SalesPersons.Where(x=>x.Id == car.SalesPersonId)
    .Select(x=>x.Car));

现在假设salespersons 表和Cars 表中有一个CountryId 列

我需要检测上面的 IQueryable 正在使用 Cars 和 SalesPerson

然后我将添加到 IQueryable 所以它变成

var cars = await (from car in DbContext.Cars
    from salesperson in DbContext.SalesPersons.Where(x=>x.Id == car.SalesPersonId).Select(x=>x.Car)
    .Where(car.CountryId = 1).Where(salesPerson.CountryId = 1);

所以我们基本上是在运行时自动添加一个过滤器

干杯

保罗

  • 您可以添加更多详细信息吗?为什么需要它,因为没有记录的方法可以做到这一点。还有 TPT 查询,这使事情变得复杂。
  • 也许你只需要Global Query Filters。乍一看,这是需要的。
  • 这看起来很强大,但是我如何将活动租户作为瞬态注入到 TenantService 中(我假设)
  • 将属性TenantId 添加到DbContext
  • 您可以将此添加为答案吗?

标签: entity-framework-core


【解决方案1】:

不需要为您的任务分析 LINQ 查询。对于按租户过滤,有Global Query Filters。配置 EF Core 后,应为已定义查询过滤器的每个实体应用过滤器。

public class TenantContext : DbContext
{
    public int? TenantId { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        ... // entities configuration

        modelBuilder.Entity<Some>().HasQueryFilter(e => TenantId == null || TenantId == e.TenantId)
    }
}

查询数据之前所需的一切 - 为上下文设置 TenantId

context.TeantId = 2;
context.Some.ToList() // table will be filtered by TenantId == 2

我准备了如何在一个函数调用中为所有实体应用租户过滤器的小示例:

public class TenantContext : DbContext
{
    public int? TenantId { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        ... // entities configuration

        ApplyTenantQueryFilters(modelBuilder, "TenantId", () => TenantId);
    }

    private void ApplyTenantQueryFilters<TProp>(ModelBuilder builder, string tenantPropName, Expression<Func<TProp>> tenantPropExpr)
    {
        foreach (var entityType in builder.Model.GetEntityTypes())
        {
            var tenantProp = entityType.GetProperties().FirstOrDefault(p => p.Name == tenantPropName);
            if (tenantProp == null)
                continue;

            var entityParam = Expression.Parameter(entityType.ClrType, "e");

            var contextTenantPropAccess = tenantPropExpr.Body;

            var propertyExpression = GetPropertyExpression(entityParam, tenantProp);
            if (propertyExpression.Type != contextTenantPropAccess.Type)
                propertyExpression = Expression.Convert(propertyExpression, contextTenantPropAccess.Type);

            // ctx.TenantId == null || ctx.TenantId == e.TenantId
            var filterBody = (Expression)Expression.OrElse(
                Expression.Equal(contextTenantPropAccess, Expression.Default(contextTenantPropAccess.Type)),
                Expression.Equal(contextTenantPropAccess,
                    propertyExpression));

            var filterLambda = entityType.GetQueryFilter();

            // we have to combine filters
            if (filterLambda != null)
            {
                filterBody = ReplacingExpressionVisitor.Replace(entityParam, filterLambda.Parameters[0], filterBody);
                filterBody = Expression.AndAlso(filterLambda.Body, filterBody);
                filterLambda = Expression.Lambda(filterBody, filterLambda.Parameters);
            }
            else
            {
                filterLambda = Expression.Lambda(filterBody, entityParam);
            }

            entityType.SetQueryFilter(filterLambda);
        }
    }

    private static Expression GetPropertyExpression(Expression objExpression, IProperty property)
    {
        Expression propExpression;
        if (property.PropertyInfo == null)
        {
            // 'property' is Shadow property, so call via EF.Property(e, "name")
            propExpression = Expression.Call(typeof(EF), nameof(EF.Property), new[] { property.ClrType },
                objExpression, Expression.Constant(property.Name));
        }
        else
        {
            propExpression = Expression.MakeMemberAccess(objExpression, property.PropertyInfo);
        }

        return propExpression;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-22
    相关资源
    最近更新 更多