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);
builder.cz
Posted by: Jarda Jirava
Last revised: 22 Jul, 2009 02:43 AM History

Comments

Site Gen
Site Gen
11 Jan, 2012 06:48 PM

Somebody looking for ways to create Sites automatically? There is a content generation tool named argo content that can build complete sites on autopilot.

Your Comments

Used for your gravatar. Not required. Will not be public.
Posting code? Indent it by four spaces to make it look nice. Learn more about Markdown.

Preview