展开实体框架 6 中的查询表达式

本文关键字:查询 查询表 表达式 实体 框架 | 更新日期: 2023-09-27 18:35:13

我有ParentItem应该应用安全修整。因此,有一个SecurityTrimmingExpressionFactory将为父元素构建一个Expression<Func<ParentItem, bool>>

安全性修整表达式工厂

public static Expression<Func<ParentItem, bool>> CreateTrimming(currentUser)
{
   return parentItem => parentItem.OwnerId == currentUser.Id;    
}

在我的 WebAPI 控制器中,我想接收父元素的子项。我会这样写的正常方式

WebAPI 控制器 (Get)

return Entities.ChildItems.Where(c => c.parentId == <some id>);

完全没有问题,但没有安全修整。

如果我想在这里应用我的安全修整(目前我正在使用 LinqKit 使用父项构建表达式树)

具有修剪功能的 WebAPI 控制器 (Get)

var expr = TrimmingExpressionsFactory.CreateParentTrimming(this.CurrentUser);
return Entities.ChildItems
                       .AsExpandable()
                       .Where(childItem => expr.Invoke(childItem.ParentItem)
                       .Where(c => c.parentId == <some id>)
                );

一切正常。

现在的问题是外部库(如LinqKit)在当前环境中是被禁止的(在我看来:错误的决策;))。没有外部库,有没有另一种方法可以使用依赖实体扩展或调用查询表达式?

已经尝试使用.AsEnumerable()来解决此问题(通常在 Web 中发现这是解决方法),但对于大型数据集来说,这不是可接受的解决方案。

展开实体框架 6 中的查询表达式

您可以使用我的答案中的小助手实用程序将表达式的一部分定义为 c# 中的变量:

public static class ExpressionUtils
{
    public static Expression<Func<TOuter, TResult>> Bind<TOuter, TInner, TResult>(this Expression<Func<TOuter, TInner>> source, Expression<Func<TInner, TResult>> resultSelector)
    {
        var body = new ParameterExpressionReplacer { source = resultSelector.Parameters[0], target = source.Body }.Visit(resultSelector.Body);
        var lambda = Expression.Lambda<Func<TOuter, TResult>>(body, source.Parameters);
        return lambda;
    }
    public static Expression<Func<TOuter, TResult>> ApplyTo<TInner, TResult, TOuter>(this Expression<Func<TInner, TResult>> source, Expression<Func<TOuter, TInner>> innerSelector)
    {
        return innerSelector.Bind(source);
    }
    class ParameterExpressionReplacer : ExpressionVisitor
    {
        public ParameterExpression source;
        public Expression target;
        protected override Expression VisitParameter(ParameterExpression node)
        {
            return node == source ? target : base.VisitParameter(node);
        }
    }
}

示例案例中的用法为:

var filter = TrimmingExpressionsFactory.CreateParentTrimming(this.CurrentUser)
    .ApplyTo((ChildItem childItem) => childItem.ParentItem);
return Entities.ChildItems
    .Where(filter)
    .Where(c => c.parentId == <some id>)
);