C # лямбда IN ошибка предложения - PullRequest
4 голосов
/ 29 июля 2011

У меня проблемы с созданием предложения IN с использованием C # и lambdas.

У меня есть следующий метод GetUserList(string filtersByRoles)

Переменная string filtersByRoles может содержать значение, разделенное запятыми, например: «1,2» или «1,2,3» или «1,3,4» и т. Д. ... каждое число представляет собой уникальное число Роль (другими словами, RoleId).

У меня есть следующий лямбда-запрос C #:

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 не распознает метод 'Boolean Содержит [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() и избежать выборки всех данных.

Есть ли другой способ добиться этого?

EDIT: Я использую Entity Framework 1.0 и .NET Framework 3.5

Спасибо С уважением

Винс

Ответы [ 3 ]

2 голосов
/ 29 июля 2011

Вот мои 2 цента:

Может быть, Dynamic 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 голосов
/ 29 июля 2011
0 голосов
/ 01 августа 2011

Судя по некоторым вашим ответам, мне удалось вывести что-то вроде этого:

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 'ArrayIndex' не поддерживается в LINQ для Сущности.

Отсюда и создание 4 (целых) переменных!

Теперь это работает, но может потребоваться некоторая оптимизация ...

Спасибо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...