0

I have the following Linq Query:

var query1 = qble1.Where(x => x.name == "name" && x.id == 1);

I am trying to extract the Where clause into a variable, which I can then reapply to another query when I need to.

To give you a slightly different view (and hopefully not confuse the aim of the question), I can do the following:

Expression<Func<testClass, bool>> whereClause = x => x.name == "name" && x.id == 1;             

var query1 = qble1.Where(whereClause);

and this will apply the whereClause variable to query1

I am trying to achieve the inverse of above, which is to write the query, and the extract the Where Clause into the variable whereClause eg

Expression<Func<testClass, bool>> whereClause = WhereClause of query1

Can this be done?

The reason I am trying to do this is to solve the issue I am having in this question:

C# Predicate builder with using AND with OR

Alex
  • 3,730
  • 9
  • 43
  • 94
  • Yes you can its the second parameter in the static call expression. If you know what override you want you can identify it by the name. – Filip Cordas Aug 30 '17 at 14:19
  • In other words, retrieve the `predicate` paramater that was passed to `Enumerable.Where` by just inspecting the resulting `IEnumerable`? – vc 74 Aug 30 '17 at 14:19
  • @vc74 that sounds about right to me – Alex Aug 30 '17 at 14:19
  • @FilipCordas can you provide more detail please, I do not fully understand your comment – Alex Aug 30 '17 at 14:20
  • @Alex Under the hood Where returns a `WhereEnumerableIterator` instance which is a private class and which holds a `predicate` field so it should be possible using reflection – vc 74 Aug 30 '17 at 14:22
  • @vc74 can you provide an example implementation please? – Alex Aug 30 '17 at 14:24
  • 1
    @Alex Why are you trying to do that? Why don't you just build your predicates and then assign them? – johnny 5 Aug 30 '17 at 14:27
  • @johnny5 because the predicates are built dynamically in a different function – Alex Aug 30 '17 at 14:29
  • I still do not understand what you are trying to achieve. Do you want to compose a lambda dynamically based on multiple lambdas and then apply the composed lambda on an IEnumerable (similar to a query builder)? – Vikhram Aug 30 '17 at 14:33
  • @vc74: That is not entirely correct. I got curious with this question so I set out to test it. Apparently, the 'Where' function returns different types of enumerators and it looks like the runtime decides which one based on the arguments. They are private and access to its members is not possible, even with reflection. Weird... – JuanR Aug 30 '17 at 14:42
  • @Juan Correct, it returns an optimized implementation in case of array, list... – vc 74 Aug 30 '17 at 14:44
  • @Alex, so have that function return the expressions and the join them all together. Or better yet, why isn't that function building your full predicate before returning an IQueryable. It doesn't sound componentized if you don't have a single object building your query – johnny 5 Aug 30 '17 at 15:08

4 Answers4

1

There seams to be a lot of confusion in the answers in regards to IEnumerable and IQueryable in the answers so I will try to help. First of all IEnumerables work with compiled code and IQueryable with expressions. The Expression portion is accessible in any IQueryable with Expression property. It will represent you code with Linq expression tree. You can get the where part of that Expression with a visitor like so.

  static void Main(string[] args)
        {
            var data = new [] 
            {
                new TestClass{ A = "A" },
                new TestClass{ A = "" },
                new TestClass{ A = "" },
                new TestClass{ A = "" },
                new TestClass{ A = "" }
            };

            var queryData = data.AsQueryable();

            queryData = queryData.
                Where(a => a.A == "A").OrderBy(a => a.A);


            Expression<Func<TestClass, bool>> filter = ( new  ExpressionGetter<Func<TestClass, bool>>()).GetWhere(queryData);

            Console.ReadLine();
        }

        public class ExpressionGetter<T> : ExpressionVisitor
        {
            private Expression<T> filter;

            protected override Expression VisitMethodCall(MethodCallExpression node)
            {
                if (node.Method.Name == "Where")
                {
                    var a = node.Arguments[1] as UnaryExpression;
                    filter = (Expression<T>)a.Operand;

                    return node;
                }
                else
                {
                    return base.VisitMethodCall(node);
                }
            }

            public Expression<T> GetWhere<TElement>(IQueryable<TElement> queryData) 
            {
                filter = null;

                this.Visit(queryData.Expression);

                return filter;
            }
        }

BUT the is a simple example that will get you the first where it can find but a Queriable can have multiple wheres transformations and so on. I think the same is not possible with IEnumerable since the delegate references only exists in context of the method you are calling.

Filip Cordas
  • 2,531
  • 1
  • 12
  • 23
  • Great answer, and addresses the actual question – Alex Aug 31 '17 at 12:53
  • @Alex Just remember to test this as much as you can this was more a profe of concept and I am sure I missed some cases that can happen. – Filip Cordas Aug 31 '17 at 21:06
  • Yes of course - I tested it yesterday and all seems to be working - it returns the lambda expression exactly as I want for the case I am using it. – Alex Sep 01 '17 at 08:10
0

I have the following Linq Query:
var query1 = qble1.Where(x => x.name == "name" && x.id == 1);
I am trying to extract the Where clause into a variable, which I can then reapply to another query when I need to.

What does it mean? Do you mean, extract the provided lambda x => x.name == "name" && x.id == 1? If that's the case, you can simply store this lambda in a variable. var a = x => x.name == "name" && x.id == 1

To give you a slightly different view (and hopefully not confuse the aim of the question), I can do the following:
Expression<Func<testClass, bool>> whereClause = x => x.name == "name" && x.id == 1;
var query1 = qble1.Where(whereClause);
and this will apply the whereClause variable to query1

No, this will not compile, if qble1 is an IEnumerable<T>. You are passing an Expression where a function or lambda is expected. Now you can do whereClause.Compile() if that's what you wish, and then again it will apply the whereClause to qble1 and NOT to query1

I am trying to achieve the inverse of above, which is to write the query, and then extract the Where Clause into the variable whereClause eg
Expression<Func<testClass, bool>> whereClause = WhereClause of query1

What does that mean? Are you asking given an IEnumerable<T> like query1, can you extract the lambda/function that was applied to obtain that IEnumerable<T>. Does that even make sense?

You are using the term where clause loosely with LINQ, Expression and lambda and it is very difficult to comprehend what that means. You should reword your question, but I have tried to answer the literal questions being raised

Vikhram
  • 4,294
  • 1
  • 20
  • 32
-1

this where clause is a lambda expression. refer to this answer to achieve this

Josue Martinez
  • 436
  • 5
  • 14
-1

Func<IQueryable<TestClass>,IQueryable<TestClass> filterFunc = query => query.Where(x => x.name == "name" && x.id == 1);

Usage:

var refinedSet = filterFunc(originalSet);

FLSH
  • 343
  • 1
  • 5
  • 15