C# 条件表达); } 返回base.VisitMethodCall(methodCallExpression); //让这一点更加灵活的一些想法: // 1. 使用属性标记可以内联的函数[InlineableAttribute] // 2. 首先定义一个表达式,以便能够获取该表达式并用它替代函数调用: //表达式_whereIsOwnedByUser=(集合,用户)=> // { //返回set.Where(temp=>UserOwnsTemplate(user,temp)); // }; // //公共静态IQueryable WhereIsOwnedByUser(此IQueryable集合,用户) // { ////应该缓存已编译的表达式 //返回_whereIsOwnedByUser.Compile().Invoke(set,user); // } // } } }

C# 条件表达); } 返回base.VisitMethodCall(methodCallExpression); //让这一点更加灵活的一些想法: // 1. 使用属性标记可以内联的函数[InlineableAttribute] // 2. 首先定义一个表达式,以便能够获取该表达式并用它替代函数调用: //表达式_whereIsOwnedByUser=(集合,用户)=> // { //返回set.Where(temp=>UserOwnsTemplate(user,temp)); // }; // //公共静态IQueryable WhereIsOwnedByUser(此IQueryable集合,用户) // { ////应该缓存已编译的表达式 //返回_whereIsOwnedByUser.Compile().Invoke(set,user); // } // } } },c#,sql-server,entity-framework,function,C#,Sql Server,Entity Framework,Function,然后你可以这样做: public static IQueryable<DataReturn> WhereIsOwnedByUser(this IQueryable<DataReturn> set, User user) { return set.Where( ret => ret.Entity.Id == user.Entity.Id && UserOwn

然后你可以这样做:

public static IQueryable<DataReturn> WhereIsOwnedByUser(this IQueryable<DataReturn> set, User user)
{
    return set.Where(
        ret =>
            ret.Entity.Id == user.Entity.Id
            &&
            UserOwnsTemplate(user, ret.Request.Template)
    )
    .InlineFunctions();
}
publicstaticiqueryable WhereIsOwnedByUser(此IQueryable集合,用户)
{
返回集。在哪里(
ret=>
ret.Entity.Id==user.Entity.Id
&&
UserOwnsTemplate(用户,ret.Request.Template)
)
.InlineFunctions();
}

关于第二个要点,我认为AndAlso位不需要任何表达式树争论。您始终可以执行
set.Where(表达式).Where(另一个表达式)
。困难在于您的表达式依赖于用户,并且您希望将其应用于IQueryable根目录的不同路径(temp vs.ret.Request.Template)。如果不构建自己的表达式,我看不出如何解决这些问题。也许有另一种方法可以解决这个问题,但我希望它涉及到实质性地更改您正在进行的查询。重复?一些观点:使用AOP框架(重写部分代码的预构建步骤),运行时成本将为零。您只需使用属性标记函数,AOP将用函数的内容替换函数调用。可惜Roslyn目前只支持设计时重写:
public static IQueryable<Template> WhereIsOwnedByUser(this IQueryable<DataReturn> set, User user)
{
    return set.Where(ret=>
        ret.Entity.Id == user.Entity.Id
        &&
        ret.Request.Template.Requests
            .Where(req => req.WasSent)
            .OrderByDescending(req => req.DueDate)
            .Take(2)
            .SelectMany(req => req.RequestRecipients.Select(reqRecip => reqRecip.Recipient.Id))
            .Contains(user.Id));
}
private static bool UserOwnsTemplate(User user, Template temp)
{
    return temp.Requests
               .Where(req => req.WasSent)
               .OrderByDescending(req => req.DueDate)
               .Take(2)
               .SelectMany(req => req.RequestRecipients.Select(reqRecip => reqRecip.Recipient.Id))
               .Contains(user.Id);
}

public static IQueryable<Template> WhereIsOwnedByUser(this IQueryable<Template> set, User user)
{
    return set.Where(temp => UserOwnsTemplate(user, temp));
}

public static IQueryable<DataReturn> WhereIsOwnedByUser(this IQueryable<DataReturn> set, User user)
{
    return set.Where(
        ret =>
            ret.Entity.Id == user.Entity.Id
            &&
            UserOwnsTemplate(user, ret.Request.Template)
    );
}
public static class MyLinqExtensions
{
    public static IQueryable<T> InlineFunctions<T>(this IQueryable<T> queryable)
    {
        var expression = TransformExpression(queryable.Expression);
        return (IQueryable<T>)queryable.Provider.CreateQuery(expression);
    }

    private static Expression TransformExpression(System.Linq.Expressions.Expression expression)
    {
        var visitor = new InlineFunctionsExpressionVisitor();
        return visitor.Visit(expression);
    }

    private class InlineFunctionsExpressionVisitor : System.Linq.Expressions.ExpressionVisitor
    {
        protected override System.Linq.Expressions.Expression VisitMethodCall(System.Linq.Expressions.MethodCallExpression methodCallExpression)
        {   
            if (methodCallExpression.Method.IsStatic
                && methodCallExpression.Method.DeclaringType == typeof(MyDeclaringType)
                && methodCallExpression.Method.Name == "WhereIsOwnedByUser")
            {
                var setArgumentExpression = methodCallExpression.Arguments[0];
                var userArgumentExpression = methodCallExpression.Arguments[1];
                var methodInfo = ... // Get typeof(IQueryable<Template>).MethodInfo
                var whereConditionExpression = ...// Build where condition and use userArgumentExpression
                return Expression.MethodCallExpression(methodInfo, setArgumentExpression, whereConditionExpression);
            }
            return base.VisitMethodCall(methodCallExpression);


            // Some ideas to make this more flexible:
            // 1. Use an attribute to mark the functions that can be inlined [InlinableAttribute]
            // 2. Define an Expression<Func<>> first to be able to get the Expression and substritute the function call with it:
            // Expression<Func<IQueryable<Template>, User, IQueryable<Template>>> _whereIsOwnedByUser = (set, user) => 
            // {
            //  return set.Where(temp => UserOwnsTemplate(user, temp));
            // };
            //
            // public static IQueryable<Template> WhereIsOwnedByUser(this IQueryable<Template> set, User user)
            // {
            //  // You should cache the compiled expression
            //  return _whereIsOwnedByUser.Compile().Invoke(set, user); 
            // }
            //
        }
    }
}
public static IQueryable<DataReturn> WhereIsOwnedByUser(this IQueryable<DataReturn> set, User user)
{
    return set.Where(
        ret =>
            ret.Entity.Id == user.Entity.Id
            &&
            UserOwnsTemplate(user, ret.Request.Template)
    )
    .InlineFunctions();
}