I made a little adaptation of How to: Use Expression Trees to Build Dynamic Queries (C# and Visual Basic.
To make it easier to understand, I’ll create the class Cliente
.
public class Cliente {
public string Nome { get; set;}
public int RG { get; set;}
public int CPF { get; set;}
public Cliente () : this ("", 0, 0) { }
public Cliente(string nome, int rg, int cpf) {
this.Nome = nome;
this.RG = rg;
this.CPF = cpf;
}
public override string ToString() {
return Nome + "\t" + RG + "\t" + CPF + "\n";
}
}
After creating customers, I will make a filter to return those with Name equal to Mario or that has the CPF equal to 100, done this I will order them by RG, the expression would look like this:
clientes.Where(cliente => cliente.Nome == "Mario" || cliente.CPF == 100)
.OrderBy(cliente => cliente.RG)
To create it dynamically, you can do it this way:
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
class Program
{
static void Main()
{
// cria os clientes
Cliente cliente1 = new Cliente("Mario", 963, 222);
Cliente cliente2 = new Cliente("Carlos", 183, 444);
Cliente cliente3 = new Cliente("Pedro", 722, 666);
Cliente cliente4 = new Cliente("Mario", 737, 888);
Cliente cliente5 = new Cliente("Maria", 159, 100);
Cliente cliente6 = new Cliente("Carla", 194, 240);
Cliente cliente7 = new Cliente("Mario", 10, 19);
// adiciona os clientes em uma lista
List<Cliente> listClientes = new List<Cliente>();
listClientes.Add(cliente1);
listClientes.Add(cliente2);
listClientes.Add(cliente3);
listClientes.Add(cliente4);
listClientes.Add(cliente5);
listClientes.Add(cliente6);
listClientes.Add(cliente7);
// recupera o IQueryable da lista de clientes
IQueryable<Cliente> queryableData = listClientes.AsQueryable<Cliente>();
// cria o parâmetro a ser utilizado na consulta
ParameterExpression pe = Expression.Parameter(typeof(Cliente), "cliente");
// expressão 'cliente.Nome == "Mario"'
Expression column = Expression.Property(pe, typeof(Cliente).GetProperty("Nome"));
Expression value = Expression.Constant("Mario");
Expression expr = Expression.Equal(column, value);
// expressão 'cliente.CPF == 100'
column = Expression.Property(pe, typeof(Cliente).GetProperty("CPF"));
value = Expression.Constant(100, typeof(int));
Expression expr2 = Expression.Equal(column, value);
// expressão '(cliente.Nome == "Mario" || cliente.CPF == 100)'
Expression predicateBody = Expression.OrElse(expr, expr2);
// expressão 'queryableData.Where(cliente =>
// (cliente.Nome == "Mario" || cliente.CPF == 100))'
MethodCallExpression whereCallExpression = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { queryableData.ElementType },
queryableData.Expression,
Expression.Lambda<Func<Cliente, bool>>(predicateBody,
new ParameterExpression[] { pe }));
// expressão 'cliente.RG'
Expression expr3 = Expression.Property(pe, typeof(Cliente).GetProperty("RG"));
// expressão 'whereCallExpression.OrderBy(cliente => cliente.RG)'
MethodCallExpression orderByCallExpression = Expression.Call(
typeof(Queryable),
"OrderBy",
new Type[] { queryableData.ElementType, typeof(int) },
whereCallExpression,
Expression.Lambda<Func<Cliente, int>>(expr3, new ParameterExpression[] { pe }));
// cria e executa a query
IQueryable<Cliente> results = queryableData.Provider
.CreateQuery<Cliente>(orderByCallExpression);
// imprime resultado
Console.WriteLine("Nome\tRG\tCPF");
foreach (Cliente cliente in results)
Console.Write(cliente.ToString());
}
}
The result is:
Nome RG CPF
Mario 10 19
Maria 159 100
Mario 737 888
Mario 963 222
You can also create a generic method:
public static IQueryable<T> Find<T>(List<T> list, string column, object value,
string columnOrder)
{
// recupera o IQueryable da lista
IQueryable<T> queryable = list.AsQueryable<T>();
// cria o parâmetro a ser utilizado na consulta
ParameterExpression pe = Expression.Parameter(typeof(T), "param");
// expressão 'param.column == value'
Expression columnExp = Expression.Property(pe, typeof(T).GetProperty(column));
Expression valueExp = Expression.Constant(value);
Expression expr = Expression.Equal(columnExp, valueExp);
// expressão 'queryable.Where(param => param.column == value)'
MethodCallExpression whereCallExpression = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { queryable.ElementType },
queryable.Expression,
Expression.Lambda<Func<T, bool>>(expr, new ParameterExpression[] { pe }));
// expressão 'param.columnOrder'
Expression expr2 = Expression.Property(pe, typeof(T).GetProperty(columnOrder));
// expressão 'whereCallExpression.OrderBy(param => param.columnOrder)'
MethodCallExpression orderByCallExpression = Expression.Call(
typeof(Queryable),
"OrderBy",
new Type[] { queryable.ElementType, expr2.Type },
whereCallExpression,
Expression.Lambda(expr2, new ParameterExpression[] { pe }));
// cria e executa a query
IQueryable<T> results = queryable.Provider.CreateQuery<T>(orderByCallExpression);
return results;
}
To use it, enter the parameters as shown below:
IQueryable<Cliente> results = Find(listClientes, "Nome", "Mario", "CPF");
Resulting in:
Nome RG CPF
Mario 10 19
Mario 963 222
Mario 737 888
If you need to access more attributes of the object or call some method, you can do so:
// exemplo base, considerando que a classe Cliente possui o atributo Endereco,
// que por sua vez possui o atributo Logradouro, teríamos algo assim:
// param.Endereco.Logradouro.ToLower() == "avenida paulista"
// que pode ser feito conforme mostrado abaixo
[...]
// cria o parâmetro a ser utilizado na consulta
ParameterExpression pe = Expression.Parameter(typeof(Cliente), "param");
// expressão 'param.Endereco'
Expression columnEndereco = Expression.Property(pe, typeof(Cliente).GetProperty("Endereco"));
// expressão 'param.Endereco.Logradouro'
Expression columnLogradouro = Expression.Property(columnEndereco, typeof(Endereco)
.GetProperty("Logradouro"));
// expressão 'param.Endereco.Logradouro.ToLower()'
Expression columnToLower = Expression.Call(columnLogradouro, typeof(string).GetMethod("ToLower"));
Expression columnValue = Expression.Constant("avenida paulista");
// expressão 'param.Endereco.Logradouro.ToLower() == "avenida paulista"'
Expression expr = Expression.Equal(columnToLower, columnValue);
[...]
I believe that with this you have already managed to have a basis to do what you need.
Extras
Expression Members
How to a Compose a Linq Expression to call Orderby on a set of entities?
Generic Methods (C Programming Guide#)
You already have some code ready to put in your question?
– Leonel Sanches da Silva
Maybe if you give an example of the application it would be easier to understand
– Richard Dias