Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将OrderBy替换为LINQ查询中的Where_C#_Linq_Azure Cosmosdb_Expressionbuilder - Fatal编程技术网

C# 将OrderBy替换为LINQ查询中的Where

C# 将OrderBy替换为LINQ查询中的Where,c#,linq,azure-cosmosdb,expressionbuilder,C#,Linq,Azure Cosmosdb,Expressionbuilder,CosmosDb存在一个已知问题,如果使用orderby子句,它将排除未定义此属性的文档 为了解决这个问题,我正在尝试创建一个功能,该功能接受LINQ查询,并用检查未定义属性的文档来替换Order子句,这样我们就可以运行两个查询并合并结果 因此: 将成为: ordersDb.Where(x => x.Name == customerName) .Where(x => !x.CompanyName.IsDefined()) // IsDefined is a built in Cosm

CosmosDb
存在一个已知问题,如果使用
orderby
子句,它将排除未定义此属性的文档

为了解决这个问题,我正在尝试创建一个功能,该功能接受LINQ查询,并用检查未定义属性的文档来替换
Order
子句,这样我们就可以运行两个查询并合并结果

因此:

将成为:

ordersDb.Where(x => x.Name == customerName)
.Where(x => !x.CompanyName.IsDefined()) // IsDefined is a built in CosmosDb function
使用ExpressionBuilder,我创建了以下内容。但是,我在尝试将表达式作为Where方法调用时遇到问题-:

private sealed class OrderByToIsNotDefinedVisitor : ExpressionVisitor
{
    protected override Expression VisitMethodCall(MethodCallExpression node)
    {
        if (node.Method.DeclaringType == typeof(Queryable) &&
            (node.Method.Name == "OrderBy" || node.Method.Name == "OrderByDescending"))
        {
            // Get the IsDefined method
            var methodIsDefined = typeof(TypeCheckFunctionsExtensions).GetMethod("IsDefined",
                BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null,
                new Type[] { typeof(object) }, null);

            // Apply the IsDefined method to the property that was being used for OrderBy
            var isDefinedItem = Expression.Call(methodIsDefined, node.Arguments[1]);

            // Alter the expression to check for !IsDefined()
            var isNotDefinedItem = Expression.Not(isDefinedItem);

            var entityType = node.Method.GetGenericArguments()[0];

            var genericWhere = BuildGenericWhere();

            var methodWhere = genericWhere.MakeGenericMethod(entityType);

            var param = Expression.Parameter(entityType);

            Expression newExpression =
                Expression.Call(
                    methodWhere,
                    node.Arguments[0],
                    Expression.Lambda(
                        typeof(Func<,>).MakeGenericType(entityType, typeof(bool)),
                        isNotDefinedItem,
                        param));

            return newExpression;
        }

        return base.VisitMethodCall(node);
    }
}

private static MethodInfo BuildGenericWhere()
{
    var genericWhereMethod = typeof(Enumerable).GetMethods(BindingFlags.Public | BindingFlags.Static)
        .Where(x => x.Name == "Where" && x.GetGenericArguments().Length == 1)
        .Select(x => new { Method = x, Parameters = x.GetParameters() })
        .Where(x => x.Parameters.Length == 2 &&
                    x.Parameters[0].ParameterType.IsGenericType &&
                    x.Parameters[0].ParameterType.GetGenericTypeDefinition() == typeof(IEnumerable<>) &&
                    x.Parameters[1].ParameterType.IsGenericType &&
                    x.Parameters[1].ParameterType.GetGenericTypeDefinition() == typeof(Func<,>))
        .Select(x => x.Method)
        .Single();

    return genericWhereMethod;
}
……然而,这导致:

System.ArgumentException:静态方法需要空实例, 非静态方法需要非空实例

首先,我们认为我们只能使用文档的属性进行排序,而不能使用派生值

因此,对于我来说,我也建议您遵循@Paul在评论中提到的建议:从cosmos db查询所有匹配的数据,然后尝试对结果列表进行排序并获取最上面的元素。我相信您已经知道表达式:


因为您必须获取最上面的元素,并且如果匹配的数据集足够大,那么无论您使用LINQ还是SQL,都会遇到阈值,可以通过
延续令牌
来解决

Try:ordersDb.Select(x=>x).OrderBy(x=>x.CompanyName)您可能已经考虑过这一点,但是您可以通过从查询中删除OrderBy并在客户端对结果进行排序来实现您的目标。这将允许您通过对数据库的一次调用而不是两次调用来执行操作。好建议@Paul,在前端进行排序将可行,但我们实际上只想返回前10行,这样做可能会涉及将大量额外数据带到客户端。嗨,这里有任何更新吗?我的回答对您有帮助吗?
private sealed class OrderByToIsNotDefinedVisitor : ExpressionVisitor
{
    protected override Expression VisitMethodCall(MethodCallExpression node)
    {
        if (node.Method.DeclaringType == typeof(Queryable) &&
            (node.Method.Name == "OrderBy" || node.Method.Name == "OrderByDescending"))
        {
            // Get the IsDefined method
            var methodIsDefined = typeof(TypeCheckFunctionsExtensions).GetMethod("IsDefined",
                BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null,
                new Type[] { typeof(object) }, null);

            // Apply the IsDefined method to the property that was being used for OrderBy
            var isDefinedItem = Expression.Call(methodIsDefined, node.Arguments[1]);

            // Alter the expression to check for !IsDefined()
            var isNotDefinedItem = Expression.Not(isDefinedItem);

            var entityType = node.Method.GetGenericArguments()[0];

            var genericWhere = BuildGenericWhere();

            var methodWhere = genericWhere.MakeGenericMethod(entityType);

            var param = Expression.Parameter(entityType);

            Expression newExpression =
                Expression.Call(
                    methodWhere,
                    node.Arguments[0],
                    Expression.Lambda(
                        typeof(Func<,>).MakeGenericType(entityType, typeof(bool)),
                        isNotDefinedItem,
                        param));

            return newExpression;
        }

        return base.VisitMethodCall(node);
    }
}

private static MethodInfo BuildGenericWhere()
{
    var genericWhereMethod = typeof(Enumerable).GetMethods(BindingFlags.Public | BindingFlags.Static)
        .Where(x => x.Name == "Where" && x.GetGenericArguments().Length == 1)
        .Select(x => new { Method = x, Parameters = x.GetParameters() })
        .Where(x => x.Parameters.Length == 2 &&
                    x.Parameters[0].ParameterType.IsGenericType &&
                    x.Parameters[0].ParameterType.GetGenericTypeDefinition() == typeof(IEnumerable<>) &&
                    x.Parameters[1].ParameterType.IsGenericType &&
                    x.Parameters[1].ParameterType.GetGenericTypeDefinition() == typeof(Func<,>))
        .Select(x => x.Method)
        .Single();

    return genericWhereMethod;
}
var updatedQueryExpression = Expression.Call(node.Arguments[0], methodWhere, isNotDefinedItem);

return updatedQueryExpression; 
var firstFiveArrivals = myList.OrderBy(i => i.ArrivalTime).Take(5);