C#lambda IN子句错误

时间:2011-07-29 15:01:38

标签: c# linq entity-framework lambda

我在使用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

由于 真诚地

文斯

3 个答案:

答案 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个(整数)变量!

它现在有效但可能需要一些优化......

由于