How to generate OR comparisons dynamically with LINQ?

3

I have a query where I should get certain values by comparing if a column is equal to a X value.

X is an array that can have 1 to 4 values.

How can I in my query with LINQ dynamically mount these OR ?

Below is how my code looks:

public List<Meta> ListaMetasDeCategorias(List<CategoriaMetaOrgao> ListaCategoriaMetaOrgao, int orgaoId, int temporadaId)
{
    List<int> arrayIdCategorias = new List<int>();
    foreach(CategoriaMetaOrgao categoriaMetaOrgao in ListaCategoriaMetaOrgao)
        arrayIdCategorias.Add(categoriaMetaOrgao.CategoriaMeta.categoriaMetaId);

    var q = from a in Repository.Context.Meta
            where a.Temporada.temporadaId == temporadaId
            && a.Orgao.orgaoId == orgaoId
            && (a.CategoriaMeta.categoriaMetaId == arrayIdCategorias[0] ||
            a.CategoriaMeta.categoriaMetaId == arrayIdCategorias[1] ||
            a.CategoriaMeta.categoriaMetaId == arrayIdCategorias[2] ||
            a.CategoriaMeta.categoriaMetaId == arrayIdCategorias[3])
            select a;

    return q.ToList();
}

In the excerpt below, how can I compare dynamically? Because the array will not always have the 4 values.

a.CategoriaMeta.categoriaMetaId == arrayIdCategorias[0] ||
a.CategoriaMeta.categoriaMetaId == arrayIdCategorias[1] ||
a.CategoriaMeta.categoriaMetaId == arrayIdCategorias[2] ||
a.CategoriaMeta.categoriaMetaId == arrayIdCategorias[3]
    
asked by anonymous 05.04.2017 / 17:03

2 answers

4

As you use version 1 of the Entity Framework , also known as version 3.5, I see 2 possibilities to solve the problem.

1. One of them is to create an extension method for this.

public static IQueryable<TEntity> WhereIn<TEntity, TValue>
(
    this ObjectQuery<TEntity> query,
    Expression<Func<TEntity, TValue>> selector,
    IEnumerable<TValue> collection
)
{
    if (selector == null) throw new ArgumentNullException("selector");
    if (collection == null) throw new ArgumentNullException("collection");
    if (!collection.Any())
        return query.Where(t => false);

    ParameterExpression p = selector.Parameters.Single();

    IEnumerable<Expression> equals = collection.Select(value =>
       (Expression)Expression.Equal(selector.Body,
            Expression.Constant(value, typeof(TValue))));

    Expression body = equals.Aggregate((accumulate, equal) =>
        Expression.Or(accumulate, equal));

    return query.Where(Expression.Lambda<Func<TEntity, bool>>(body, p));
}

To use it:

public List<Meta> ListaMetasDeCategorias(List<CategoriaMetaOrgao> ListaCategoriaMetaOrgao, int orgaoId, int temporadaId)
{
    List<int> arrayIdCategorias = new List<int>();
    foreach(CategoriaMetaOrgao categoriaMetaOrgao in ListaCategoriaMetaOrgao)
        arrayIdCategorias.Add(categoriaMetaOrgao.CategoriaMeta.categoriaMetaId);

    var q = from a in Repository.Context.Meta
            where a.Temporada.temporadaId == temporadaId
            && a.Orgao.orgaoId == orgaoId
            select a;

    q.WhereIn(a => a.CategoriaMeta.categoriaMetaId, arrayIdCategorias);

    return q.ToList();
}

2. The other solution and I do not recommend much is to transform your query to a list and then do the Contains filter, the problem this way is that you are not doing the filter on select, so maybe making your query heavier.

public List<Meta> ListaMetasDeCategorias(List<CategoriaMetaOrgao> ListaCategoriaMetaOrgao, int orgaoId, int temporadaId)
{
    List<int> arrayIdCategorias = new List<int>();
    foreach(CategoriaMetaOrgao categoriaMetaOrgao in ListaCategoriaMetaOrgao)
        arrayIdCategorias.Add(categoriaMetaOrgao.CategoriaMeta.categoriaMetaId);

    var q = from a in Repository.Context.Meta
            where a.Temporada.temporadaId == temporadaId
            && a.Orgao.orgaoId == orgaoId
            select a;

    var y = q.ToList().Where( a => arrayIdCategorias.Contains(a.CategoriaMeta.categoriaMetaId));


    return y;
}

Note: If you used Entity Framework 4 or higher, you could use Contains , it takes a list and checks if an element is in that list.

public List<Meta> ListaMetasDeCategorias(List<CategoriaMetaOrgao> ListaCategoriaMetaOrgao, int orgaoId, int temporadaId)
{
    List<int> arrayIdCategorias = new List<int>();
    foreach(CategoriaMetaOrgao categoriaMetaOrgao in ListaCategoriaMetaOrgao)
        arrayIdCategorias.Add(categoriaMetaOrgao.CategoriaMeta.categoriaMetaId);

    var q = from a in Repository.Context.Meta
            where a.Temporada.temporadaId == temporadaId
            && a.Orgao.orgaoId == orgaoId
            && arrayIdCategorias.Contains(a.CategoriaMeta.categoriaMetaId)
            select a;

    return q.ToList();
}
    
05.04.2017 / 17:11
1

The List called arrayIdCategorias has method Any where it will scan array in order to satisfy the condition.

In the case below, it scans the arrayIdCategorias for if there is any value int that is equal to a.CategoriaMeta.categoriaMetaId .

If it finds Any returns true , if not false .

public List<Meta> ListaMetasDeCategorias(List<CategoriaMetaOrgao> ListaCategoriaMetaOrgao, int orgaoId, int temporadaId)
{
    List<int> arrayIdCategorias = new List<int>();
    foreach(CategoriaMetaOrgao categoriaMetaOrgao in ListaCategoriaMetaOrgao)
        arrayIdCategorias.Add(categoriaMetaOrgao.CategoriaMeta.categoriaMetaId);

    var q = from a in Repository.Context.Meta
        where a.Temporada.temporadaId == temporadaId
        && a.Orgao.orgaoId == orgaoId
        && arrayIdCategorias.Any(b=>b == a.CategoriaMeta.categoriaMetaId)
        select a;

    return q.ToList();
}
    
05.04.2017 / 18:13