我在使用C#和lambdas创建IN子句时遇到问题。
我有以下方法GetUserList(string filtersByRoles)
变量string filtersByRoles
可以包含逗号分隔的值,例如:“1,2”或“1,2,3”或“1,3,4”等...每个数字代表唯一角色的编号(换句话说,RoleId)。
然后我有以下C#lambda查询:
var query = _userRepository.GetUserList();
返回IQueryable<User>
,其中User
是我的EntityFramework中的表格。
一旦我验证filtersByRoles
参数是否为空或空,我需要制作一个IN
子句,例如:
if (!string.IsNullOrEmpty(filtersByRoles))
{
//Convert *filtersByRoles* to an array of integers
int[] myArray = filtersByRoles.Split(',').Select(x => int.Parse(x)).ToArray();
//Make the IN clause
query = query.Where(u => myArray.Contains(u.RoleId));
}
上面的代码编译了......但是在RUNTIME它失败并出现以下错误消息:
LINQ to Entities无法识别方法'布尔值 包含[的Int32](System.Collections.Generic.IEnumerable`1 [System.Int32] 'int32)'方法,并且此方法无法转换为商店 表达
我设法找到一种解决方法,但它涉及调用.ToList()
方法,我认为该方法从我的数据库中获取所有数据,然后添加Where()子句。
但这不会破坏目的或产生一些性能问题吗?
这就是我所做的:
if (!string.IsNullOrEmpty(filtersByRoles))
{
string[] myArray = filtersByRoles.Split(',');
query = query.ToList().Where(u => myArray.Contains(u.RoleId.ToString())).AsQueryable();
}
我希望不进行.ToList()
调用,避免获取所有数据。
还有另一种方法可以达到这个目的吗?
编辑: 我正在使用Entity Framework 1.0和.NET Framework 3.5
由于 真诚地
文斯
答案 0 :(得分:2)
答案 1 :(得分:2)
这是我的2美分:
动态LinQ可能有助于解决您的问题: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
您可以将Where子句构建为字符串,例如:
string sWhereClause = "1 = 1";
foreach(string rId in filtersByRoles.Split(','))
sWhereClause += " OR RoleId = " + rId;
(我建议使用StringBuilder而不是+ concat,但出于这个答案的目的,没关系)
然后
query = query.Where(sWhereClause);
我没有尝试过,但这对解决你的问题听起来很公平。即使它看起来像SQL注入......嗯,可以带来改进。
修改强> 作为第二个想法,我设法得到了这个新想法:
string filterByRoles = "1,2,3";
query = query.Where(new Func<User, bool>(u => {
return filterByRoles.Contains(u.RoleId.ToString());
})).AsQueryable();
这样,你可以在Func {...}委托中添加你想要的任何代码,只要它返回一个布尔值(我假设你的TInput是一个“用户”类,当然改为使用它一个对应你的需要)。
希望这有帮助!
答案 2 :(得分:0)
根据你的一些回复,我设法得到这样的东西:
int[] myArray = filtersByRoles.Split(',').Select(x => int.Parse(x)).ToArray();
int count = myArray.Count();
int role1;
int role2;
int role3;
int role4;
switch (myArray.Length)
{
case 1:
role1 = myArray[0];
query = query.Where(u => u.RoleId.Equals(role1));
break;
case 2:
role1 = myArray[0];
role2 = myArray[1];
query = query.Where(u => u.RoleId.Equals(role1)
|| u.RoleId.Equals(role2));
break;
case 3:
role1 = myArray[0];
role2 = myArray[1];
role3 = myArray[2];
query = query.Where(u => u.RoleId.Equals(role1)
|| u.RoleId.Equals(role2)
|| u.RoleId.Equals(role3));
break;
case 4:
role1 = myArray[0];
role2 = myArray[1];
role3 = myArray[2];
role4 = myArray[3];
query = query.Where(u => u.RoleId.Equals(role1)
|| u.RoleId.Equals(role2)
|| u.RoleId.Equals(role3)
|| u.RoleId.Equals(role4));
break;
}
直接尝试使用myArray [xxx]:
query = query.Where(u => u.RoleId.Equals(myArray[0]));
我得到了这个:
LINQ to不支持LINQ表达式节点类型'ArrayIndex' 实体。
因此创建了4个(整数)变量!
它现在有效但可能需要一些优化......
由于