EF3.5에서 “in” 쿼리문 표현을 위한 Contains 메서드 버그(?) 대응법
출처 : http://blogs.msdn.com/b/alexj/archive/2009/03/26/tip-8-writing-where-in-style-queries-using-linq-to-entities.aspx
LINQ로 “in” sql 구문을 사용하려면 Contains 확장 메서드를 사용하면 된다.
sql : select * from People where Firstname in {‘Alex’, ‘Colin’, ‘Danny’, ‘Diego’}
linq : var matches = from person in people
where names.Contains(person.Firstname)
select person;
그러나 Entity Framework 3.5에서 이 linq 구문은 Conains 메서드에서 다음과 같은 예외를 뱉어낸다.
LINQ to Entities에서 ‘Boolean Contains[Int32](System.Collections.Generic.IEnumerable`1[System.Int32], Int32)’ 메서드를 인식하지 않으므로 이 메서드는 저장소 식으로 변환될 수 없습니다.
이 문제는 EF4.0에서 발생하지 않는다. EF3.5에서도 실제 DB에 질의를 할 경우에 발생한다.
EF3.5에서 이 문제를 해결하기 위해서는 다음과 같은 표현식으로 작성하는 수 밖에 없다고 한다.
var matches = from person in people where
person.Firstname == “Alex” ||
person.Firstname == “Colin” ||
person.Firstname == “Danny” ||
person.Firstname == “Diego”
select person;
이 코드를 매번 작성하려면 어지간히 골치아픈일이 아닐 수 없다. 그래서 이러한 표현식을 만들어주는 메서드를 제시하고 있다.
public static Expression<Func<TElement, bool» BuildOrExpression<TElement, TValue>(
Expression<Func<TElement, TValue» valueSelector,
IEnumerable<TValue> values)
{
if (null == valueSelector)
throw new ArgumentNullException(“valueSelector”);
if (null == values)
throw new ArgumentNullException(“values”);
ParameterExpression p = valueSelector.Parameters.Single();
if (!values.Any())
return e => false;
var equals = values.Select(
value => (Expression)Expression.Equal(
valueSelector.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);
}