【问题标题】:Lambda IfThenElse expression with another lambda inside (for SetQueryFilter())内部带有另一个 lambda 的 Lambda IfThenElse 表达式(用于 SetQueryFilter())
【发布时间】:2020-12-19 03:24:20
【问题描述】:

我的目标是对IMutableEntityType 进行过滤,我通过CurrentTenantId 列值选择数据行。 更多上下文请见:https://github.com/dotnet/efcore/issues/23718

这已经是我做的了:

var parameter = Expression.Parameter(entityType.ClrType, "p");
                
// TODO: This filter is working, but we must prevent filtering with TenantId = 0
var workingFilter = Expression.Lambda(
    Expression.Equal(
        Expression.Property(parameter, colName),
        // See https://github.com/dotnet/efcore/issues/23718
        Expression.MakeMemberAccess(Expression.Constant(myContext), currentTenantIdMemberInfo)
        ),
    parameter);

entityType.SetQueryFilter(filter);

但是如果TenantId == 0我想获取所有实体,所以我写了这个Lambda:

var conditionalExpression = Expression.IfThenElse(
    // Check if TenantId > 0
    Expression.GreaterThan(
        Expression.MakeMemberAccess(Expression.Constant(myContext), currentTenantIdMemberInfo),
        Expression.Constant((long) 0)
        ),
    // build filter: (p) => p.{colName} == {myContext.CurrentTenantId}
    // i.e. (p) => p.TenantId == 123)
    Expression.Lambda(
        Expression.Equal(
            Expression.Property(parameter, colName),

            // See https://github.com/dotnet/efcore/issues/23718
            Expression.MakeMemberAccess(Expression.Constant(myContext), currentTenantIdMemberInfo)
            )//,
        ),
    // TenantId <= 0, so act like (p => p)
    Expression.Lambda(Expression.Constant(parameter)) // just p // TODO: Not working
    //Expression.Lambda(Expression.Constant(parameter), parameter) // p => p // TODO: Also not working...
);

var filter = Expression.Lambda(conditionalExpression);

但是在调用entityType.SetQueryFilter(filter);之后我有InvalidOperationException

'The filter expression '() => IIF((value(My.Project.MyContext).CurrentTenantId > 0), () => (p.TenantId == value(My.Project.MyContext).CurrentTenantId), () => p)' specified for entity type 'MyEntity' is invalid. The expression must accept a single parameter of type 'My.Project.MyEntity' and return bool.'

我的问题是 - 我怎样才能实现我的目标?

【问题讨论】:

    标签: c# linq lambda expression expression-trees


    【解决方案1】:

    类似的东西。您错过了将 parameter 添加到 Lambda 并在使用 lambda 时出错。还选择了最短的方法来做到这一点。

    var parameter = Expression.Parameter(entityType.ClrType, "p");
    
    // EF just needs to know that you have member access to DbContext
    var contextExpr = Expression.Constant(null, typeof(MyContext));
    var tenantExpr = Expression.MakeMemberAccess(contextExpr, currentTenantIdMemberInfo);
    
    var conditionalExpression = Expression.OrElse(
        // Check if TenantId <= 0
        Expression.LessThanOrEqual(
            tenantExpr,
            Expression.Constant((long) 0)
            ),
            Expression.Equal(
                Expression.Property(parameter, colName),
                tenantExpr
            )
        )
    );
    
    var filter = Expression.Lambda(conditionalExpression, parameter);
    
    entityType.SetQueryFilter(filter);
    

    另外你并不孤单,这个任务已经被很多图书馆完成了,例如ASP.NET Boilerplate

    为了简化此类任务,我强烈建议使用表达式树可视化器: https://github.com/agileobjects/ReadableExpressions https://github.com/zspitz/ExpressionTreeVisualizer

    【讨论】:

    • 谢谢。 3 天前我已经以同样的方式实现了它 - EF Core 团队的 Smit 更快地回答了它(请参阅我的问题中的 URL)。我将您的答案标记为已接受。圣诞快乐,新年快乐。
    猜你喜欢
    • 2013-07-02
    • 1970-01-01
    • 2021-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多