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
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
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);