内部有另一个 lambda 的 Lambda IfThenElse 表达式(对于 SetQueryFilter())
Lambda IfThenElse expression with another lambda inside (for SetQueryFilter())
我的目标是过滤 IMutableEntityType
,其中我 select 数据行按 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.'
我的问题是 - 我怎样才能实现我的目标?
像这样。您错过了将 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
我的目标是过滤 IMutableEntityType
,其中我 select 数据行按 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.'
我的问题是 - 我怎样才能实现我的目标?
像这样。您错过了将 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