How do I get values of Linq Expression
Asked Answered
M

4

6

I have a method that takes Expression type parameter, in my method i want to get values of this expression but cant find out hot to do that.

private User GetUser(Expression<Func<User, bool>> query)
{
  User user = Context.User.Where(query).FirstOrDefault();
  return user;
}

I am calling this method with different parameters like

GetUser(u => u.Username == username);

GetUser(u=> u.Email == email);

I want to change GetUser method to work with stored procedures but i need to find what is inside query parameter

I want to check if query is u.Username == username I will call GetUserByUsername SP if query is u.Email == email I will call GetuserByEmail SP

Manzoni answered 23/12, 2010 at 14:31 Comment(0)
S
8

The expression can be reduced to several expressions.

 var body = query.Body as BinaryExpression;
 if (body != null)
 {
    var left = body.Left as MemberExpression;
    if (left != null)
    {
        Console.WriteLine(left.Member.Name);   
         // You can get "Username" or "Email" here
    }
 }

By the way I think you are in a wrong direction. Think about this situation: Some other developer see your GetUser method, using it in this way:

var result = GetUser(u => u.Email.Equals("[email protected]")); //or
var another = GetUser(u => u.Username.Contains("bar"));

He would think he is correct, but in fact your method won't give his ideal result! Well you can say "never mind, I will inform them this change", but what about the days after you quitted this team/company? It's a nightmare if a method doesn't behave like its declaration.

Stark answered 23/12, 2010 at 14:50 Comment(1)
Might also want to check that the operator is equals. Don't remember off hand how to do that but I know it can (and probably should) be done.Barsky
R
1

Maybe you should use LINQ for SQL. It does exactly what you want: tear apart the expression and see what fields and comparisons you need. I don't suggest doing this manually, but if you want to, then look into the members of an Expression class, it's an expression tree and will have nodes like property access and comparison.

Rondo answered 23/12, 2010 at 14:43 Comment(0)
A
1

You could in theory walk the expression tree in query.Body to determine the intent of the function - in this case it'll be a BinaryExpression in which you'll need to check the Left and Right properties to see what's being compared.

However, I would suggest that if you're using specific SPs to do the querying then using an expression isn't really the way to go - creating separate GetUserByUsername and GetUserByEmail methods is going to be more robust unless you really want to be throwing exceptions when somebody calls GetUser with an unexpected expression.

Anvers answered 23/12, 2010 at 15:5 Comment(0)
B
0

Where accepts Func<TSource, bool> predicate, not an Expression. Check an example:

class Program
{
    private static List<int> l = new List<int> { 1, 2, 3, 4, 5 };

    static void Main(string[] args)
    {
        Console.WriteLine(GetNum(x => x > 3));
        Console.ReadKey();
    }

    private static int GetNum(Func<int, bool> predicate)
    {
        return l.Where(predicate).FirstOrDefault();
    }
}

It returns 4. So, change your function definition to private User GetUser(Func<User, bool> query)

Boru answered 23/12, 2010 at 14:44 Comment(2)
I don't think this is what the OP is looking for. If you read the end of the question, Yucel wants to call different sprocs based on which which parameter is being checked.Barsky
Where accepts an ExpressionAlrich

© 2022 - 2024 — McMap. All rights reserved.