在LINQ to Entities中没有办法再像 LINQ to SQL 中一样使用 Contains 的方法来实现sql "in" 关键字
下面代码在 LINQ to SQL 中可行 在LINQ to Entities却无法运行:
var s
=
db.Account.Select(c
=>
c.ID);
var ret
=
(from t
in
db.Profile
where
s.Contains(t.ID)
select t).ToList();
替代方法1:使用方法Any
var ids
=
db.Account.Select(c
=>
c.ID);
var ret
=
(from t
in
db.Profile
where
ids.Any(c
=>
c
==
t.UserID) select t).ToList();
使用方法Any替换法搞了好久都没法实现直接对数组Any,下列代码仍无法执行:
int
[] ids
=
new
int
[]{
10101
,
10005
,
10007
};
var ret
=
(from t
in
db.Profile
where
ids.Any(c
=>
c
==
t.UserID) select t).ToList();
于是继续Goolge寻找第二种方法,在MSDN论坛上找一个构造Lambda语句的方法
替代方法2:构造Lambda语句
private
static
Expression
<
Func
<
TElement,
bool
>>
BuildWhereInExpression
<
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);
}
调用方法:
int
[] ids
=
new
int
[]{
10101
,
10005
,
10007
};
db.Profile.Where(BuildWhereInExpression
<
Profile,
int
>
(v
=>
v.Id,ids);
该方法可也扩展为:
public
static
IQueryable
<
TElement
>
WhereIn
<
TElement, TValue
>
(
this
IQueryable
<
TElement
>
source, Expression
<
Func
<
TElement, TValue
>>
propertySelector,
params
TValue[] values)
{
return
source.Where(BuildWhereInExpression(propertySelector, values));
}
这样就可以直接使用下列方法调用
string
[] ids
=
new
string
[]{
10101
,
10005
,
10007
};
db.Profile.WhereNotIn(c
=>
c.Id,ids);
后来又看到网上有这样的解决办法
替代方法3:字符串构造
这个方法比较简单
string
[] ids
=
new
string
[]{
10101
,
10005
,
10007
};
string
csvIds
=
string
.Join(
"
,
"
, ids.Cast
<
string
>
().ToArray());
db.Profile.Where(
"
it.Id in {
"
+
csvIds
+
"
}
"
);
it是什么这里就不用说了吧!