Entity framework a IN klauzule

V konferenci o .net na builder.cz se objevil dotaz, jak sestavit SQL dotaz pomocí Entity frameworku, který by vygeneroval na výstupu omezující podmínku IN.

Jelikož v Linq to SQL je toto poměrně triviální řešení a je možné použít extenzní metodu Contains, neváhal jsem a autorovi potvrdil, že obdobně to bude i v případě Entity frameworku. Jenže pak ve mě začal hlodat červík nedůvěřivosti, vždyť to autor dotazu měl správně, tak proč to nejde. Až jsem přišel na to, že v EFv1 nelze použít Contains metodu tak, aby se vygenerovala IN klauzule.

Samozřejmě existuje řešení, kdy je možné provést celý SQL dotaz a až následně v paměti aplikovat spojení, které zajistí omezující podmínku. Je to však řešení nepříliš praktické.

Zkusil jsem tedy chvilku bádat a tady je řešení. Jedná se o to, že klauzule IN je možné reprezentovat také jako spojení jednotlivých hodnot operátorem OR. Pro lepší možnost použití je pak vytvořena extenzní metoda s názvem In a přebírající dva parametry.

public static class EFExtensions {

    private static Expression<Func<TEntity, bool>> GetIn<TEntity, TValue>(
 Expression<Func<TEntity, TValue>> propertySelector,
 IEnumerable<TValue> values) {
        var property = propertySelector.Parameters.Single();
        if ((values == null) || (!values.Any()))
            return e => false;

        var parts = values.Select(value => Expression.Equal(
 propertySelector.Body, 
 Expression.Constant(value, typeof(TValue))));
        var body = parts.Aggregate(Expression.Or);

        return Expression.Lambda<Func<TEntity, bool>>(body, property);
    } 

    public static IQueryable<TE> In<TE, TV>(this IQueryable<TE> source, Expression<Func<TE, TV>> propertySelector, 
params TV[] values) {
        return source.Where(GetIn(propertySelector, values));
    }

    public static IQueryable<TE> In<TE, TV>(this IQueryable<TE> source, Expression<Func<TE, TV>> propertySelector, 
IEnumerable<TV> values) {
        return source.Where(GetIn(propertySelector, values));
    } 
}

Použití této extenzní metody je pak velice jednoduché a demonstruje ji následující případ:

var ids = new int[] {1, 2, 3};
var data = db.TestTable.In(e => e.IntValues, ids).OrderBy(e => e.StringValues);
Add a Comment