Where dynamic Linq to SQL

Asked

Viewed 1,037 times

5

I need to build a clause where with the field and dynamic value, for example, in pure SQL would be:

WHERE :CAMPO = :VALOR

However, searching the research I could not find anything specific, I’m already performing queries in the database with a clause where fixed without problems. I cannot change dynamically, my code snippet is as follows:

string campo = "NOME";
string valor = "JOAO";

listEmpresa = db.EMPRESA.Where(...).ToList();

3 answers

5

I am working with this currently, and recommend using System.Linq.Expressions.Expression, Lambda and a little bit of Reflection for that reason.

Example:

string campo = "Campo";
string valor = "valor";

// recupera o objeto IQueryable da Context do EF
IQueryable<Empresa> query = db.EMPRESA;
// cria alias do objecto Lambda
ParameterExpression param = Expression.Parameter(typeof(Empresa), "x");
// obtem tipo da propriedade
Type type = typeof(Empresa).GetProperty(campo).PropertyType;
// cria Expression para o campo
MemberExpression propertyExpression = Expression.PropertyOrField(param, campo);
// cria Expression para o valor
ConstantExpression valueExpression = Expression.Constant(Convert.ChangeType(valor, type), type);

EQUALS EXAMPLE

// cria predicate Lambda Expression
var predicate = Expression.Lambda<Func<Empresa, bool>>(
    // aplica tipo de Filtro, no caso do exemplo Equal (campo == valor)
    Expression.Equal(propertyExpression, valueExpression)
, param);

EXAMPLE Contains (LIKE)

MethodInfo methodInfo = type.GetMethod("Contains", new[] { type });            
var predicate = Expression.Lambda<Func<Empresa, bool>>(
    // aplica tipo de Filtro, no caso do exemplo Contains (LIKE campo '%valor%')
    Expression.Call(propertyExpression, methodInfo, valueExpression)
, param);

Code continuation...

// adiciona predicate ao where da query
query = query.Where(predicate);
// executa a consulta no banco de dados
var result = query.ToList();

Source: Use string as field name in LINQ

  • thank you very much, Fernando!

  • @For the record, you can only choose one answer as correct.

4


As you want everything dynamic, there is the great package System.Linq.Dynamic who does it for you. Then with him it would be:

listEmpresa = db.EMPRESA.Where(campo + "==@0", valor).ToList();
  • but in this case, the e.Name would be dynamic, and the value "JOAO" also, I would need to pass the name of the variables in the case...

  • I updated the answer.

  • Ah! I had edited to pass "JOAO" in a variable, but did not give time... rs

  • @Andrer, you can do it like this:;var nomeParaPesquisar = "JOAO"; listEmpresa = db.EMPRESA.Where(e => e.Nome == nomeParaPesquisar).ToList();

  • 1

    @Thiagolunardi I think he wants to ride everything dynamic, then it has to be by System.Linq.Dynamic even.

  • @Thiagolunardi Looks like he needs to pass the field dynamically also.

  • thanks Gypsy, I managed to solve the problem, hugs!

  • @Gypsy Where dynamic has any risk of allowing SQL Injection (in this case in the field name, since the parameter value is set)? Or the ORM already warns itself somehow about this?

  • 1

    @Fernando The parameterization is done through SqlParameters. In addition, the treatment of variables should receive some attention from the programmer.

Show 4 more comments

2

You can also extend the System.Linq adding a WhereIf. I used it once, and it works fine.

First add extension to your project:

public static class LinqExtensions
{
    public static IQueryable<TSource> WhereIf<TSource>(
        this IQueryable<TSource> source, bool condition,
        Expression<Func<TSource, bool>> predicate)
    {
        if (!condition) return source;
        return source.Where(predicate);            
    }
}

Then use it wisely:

// a clausula WHERE somente será aplicado se variável 'condicao' for true
var resultado = MeusDados
                    .WhereIf(condicao == true, dado => dado.campo == "valor")
                    .ToList();

UPDATE:

Application example:

[HttpGet]
public async Task<IEnumerable<pessoa>> BuscarPessoas(string nome, int idade, DateTime dataNascimento)
{
    var pessoas = await Task.FromResult(_contexto.Pessoas
                      .WhereIf(!string.IsNullOrEmpty(nome), p => p.Nome.Contains(nome))
                      .WhereIf(idade > 0, p => p.Idade == idade)
                      .WhereIf(dataNascimento != null, p => p.DataNascimento = dataNascimento)
                      .ToList();
    return pessoas;
}
  • 1

    I don’t want to seem boring. But I can’t see how, using this solution, the Where field would be passed dynamically.

  • 1

    thank you so much anyway Thiago, hug!

  • You’re right @jbueno , literally, it wouldn’t be. I sent it because I would never do something like that, because I think it’s insecure, because I would accept SQL Injection, I don’t know. I would do the following, on the front choose by which field will filter on the back would make a Whereif for field face possible.

  • But believe me, it’s a pretty cool way to handle it. I like it, I think it’s super clean, and it’s fast. :)

  • @Thiagolunardi, I tried to understand how this WhereIf can help the question problem and found no relation. Can you try editing to be clearer with your answer and how it helps solve the question problem? 'Cause the way it is I don’t see much point in using it instead of Where normal!

  • @Fernando, I added an application example. See if it fits, pf?

  • @Thiagolunardi, what I don’t see in your solution is how to use the column name/dynamic property, apart from a string, which is the problem reported in the question?

  • @Fernando, Linq is strongly typed. Lambdaexpression works only with predicates. So, without using workarounds is not possible.

  • @Thiagolunardi, then his answer does not answer the question, because the main question of the question is how to create queries with dynamic field. I agree that it is a good solution to validate records before adding them to Where. But in my understanding it has no real relation to the question (I may be wrong =D). And in case the question really wants an alternative form (workarounds), and its extension is also already an alternative form. =/

Show 4 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.