Use Linq.Any() inside a Linq.Where() on CosmosDb

前端 未结 2 1981
佛祖请我去吃肉
佛祖请我去吃肉 2021-01-06 13:25

I am trying to nest an .Any() inside a .Where() clause to query a local CosmosDb emulator.

The code looks like below; where permitted

2条回答
  •  心在旅途
    2021-01-06 13:56

    After trying out numerous combination of various lambda expressions, here is what worked out for me.

    I added a StudentIds property to my DocumentModel class; redundant but used for filtering alone.

    Thereafter, I OR-ed the query with .Contains(), something like this:

    Expression> query = a => a.StudentIds.Contains(permittedStudentIds[0]);
    foreach (var id in permittedStudentIds.Skip(1))
    {
        query = query.Or(a => a.StudentIds.Contains(id));
    }
    

    and then used the query like:

    .Where(query);
    

    For the query.Or() part I used the following classes:

    // See: https://blogs.msdn.microsoft.com/meek/2008/05/02/linq-to-entities-combining-predicates/
    public static class ExpressionExtensions
    {
        public static Expression Compose(this Expression first, Expression second, Func merge)
        {
            // build parameter map (from parameters of second to parameters of first)
            var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
    
            // replace parameters in the second lambda expression with parameters from the first
            var secondBody = ParameterVistor.ReplaceParameters(map, second.Body);
    
            // apply composition of lambda expression bodies to parameters from the first expression 
            return Expression.Lambda(merge(first.Body, secondBody), first.Parameters);
        }
    
        public static Expression> And(this Expression> first, Expression> second)
        {
            return first.Compose(second, Expression.AndAlso);
        }
    
        public static Expression> Or(this Expression> first, Expression> second)
        {
            return first.Compose(second, Expression.OrElse);
        }
    }
    
    
    public class ParameterVistor : ExpressionVisitor
    {
        private readonly Dictionary map;
    
        public ParameterVistor(Dictionary map)
        {
            this.map = map ?? new Dictionary();
        }
    
        public static Expression ReplaceParameters(Dictionary map, Expression exp)
        {
            return new ParameterVistor(map).Visit(exp);
        }
    
        protected override Expression VisitParameter(ParameterExpression p)
        {
            ParameterExpression replacement;
            if (map.TryGetValue(p, out replacement))
            {
                p = replacement;
            }
            return base.VisitParameter(p);
        }
    }
    

提交回复
热议问题