Contains in Linq to Entitys
Linq to entities(LtoE) does not support “contains” as in the following Linq to Sql query:
var subquery = from product in MySandbox.Products
where product.Supplier.City.StartsWith("M")
select product.CategoryID;
var query = from category in MySandbox.Categories
where
category.CategoryName.Contains("y")
&& subquery.Contains(category.CategoryID)
select category;
the code will actually compile but throws a runtime error on the Contains. However the code can be rewritten to use Any:
var query = from category in MySandbox.Categories
where
category.CategoryName.Contains("y")
&& subquery.Any(i => i == category.CategoryID)
select category;
There is a larger issue with “contains” and code that looks like:
List ints = new List { 5, 6 };
var query2 = MySandbox.Categories.Where(e => ints.Contains(e.CategoryID));
This compiles but a runtime exception is thrown:
LINQ to Entities does not recognize the method 'Boolean Contains(Int32)' method, and this method cannot be translated into a store expression.
However there is an interesting solution at http://social.msdn.microsoft.com/forums/en-US/adodotnetentityframework/thread/095745fe-dcf0-4142-b684-b7e4a1ab59f0/
public static class QueryableExtensions
{
private static Expression<Func<TElement, bool>> GetWhereInExpression<TElement, TValue>(Expression<Func<TElement, TValue<< propertySelector, IEnumerable<TValue> values)
{
ParameterExpression p = propertySelector.Parameters.Single();
if (!values.Any())
return e => false;
var equals = values.Select(value => (Expression)Expression.Equal(propertySelector.Body, Expression.Constant(value, typeof(TValue))));
var body = equals.Aggregate<Expression>((accumulate, equal) => Expression.Or(accumulate, equal));
return Expression.Lambda<Func<TElement, bool>>(body, p);
}
///
/// Return the element that the specified property's value is contained in the specifiec values
public static IQueryable<TElemen> WhereIn<TElement, TValue>(this IQueryable<TElement> source, Expression<Func<TElement, TValu>> propertySelector, params TValue[] values)
{
return source.Where(GetWhereInExpression(propertySelector, values));
}
///
/// Return the element that the specified property's value is contained in the specifiec values
public static IQueryable<TElement> WhereIn<TElement, TValue>(this IQueryable<TElement> source, Expression<Func<TElement, TValue>> propertySelector, IEnumerable<TValue> values)
{
return source.Where(GetWhereInExpression(propertySelector, values));
}
}
var subquery = from product in MySandbox.Products
where product.Supplier.City.StartsWith("M")
select product.CategoryID;
var query = from category in MySandbox.Categories
where
category.CategoryName.Contains("y")
&& subquery.Contains(category.CategoryID)
select category;
the code will actually compile but throws a runtime error on the Contains. However the code can be rewritten to use Any:
var query = from category in MySandbox.Categories
where
category.CategoryName.Contains("y")
&& subquery.Any(i => i == category.CategoryID)
select category;
There is a larger issue with “contains” and code that looks like:
List
var query2 = MySandbox.Categories.Where(e => ints.Contains(e.CategoryID));
This compiles but a runtime exception is thrown:
LINQ to Entities does not recognize the method 'Boolean Contains(Int32)' method, and this method cannot be translated into a store expression.
However there is an interesting solution at http://social.msdn.microsoft.com/forums/en-US/adodotnetentityframework/thread/095745fe-dcf0-4142-b684-b7e4a1ab59f0/
public static class QueryableExtensions
{
private static Expression<Func<TElement, bool>> GetWhereInExpression<TElement, TValue>(Expression<Func<TElement, TValue<< propertySelector, IEnumerable<TValue> values)
{
ParameterExpression p = propertySelector.Parameters.Single();
if (!values.Any())
return e => false;
var equals = values.Select(value => (Expression)Expression.Equal(propertySelector.Body, Expression.Constant(value, typeof(TValue))));
var body = equals.Aggregate<Expression>((accumulate, equal) => Expression.Or(accumulate, equal));
return Expression.Lambda<Func<TElement, bool>>(body, p);
}
///
/// Return the element that the specified property's value is contained in the specifiec values
public static IQueryable<TElemen> WhereIn<TElement, TValue>(this IQueryable<TElement> source, Expression<Func<TElement, TValu>> propertySelector, params TValue[] values)
{
return source.Where(GetWhereInExpression(propertySelector, values));
}
///
/// Return the element that the specified property's value is contained in the specifiec values
public static IQueryable<TElement> WhereIn<TElement, TValue>(this IQueryable<TElement> source, Expression<Func<TElement, TValue>> propertySelector, IEnumerable<TValue> values)
{
return source.Where(GetWhereInExpression(propertySelector, values));
}
}
