Простой условный запрос LINQ в Entity Framework 4

Недавно я перенес этот код в Entity Framework 4, и он не работает. Очевидно, если статус не имеет значения, верните все совпадения, если он имеет значение, соответствующее значению user.StatusID == 1.

return users.SingleOrDefault(
                user =>
                user.Username == username &&
                user.EncryptedPassword == password &&
                (!status.HasValue || user.StatusID == 1)
                );

Возвращено исключение:

ArgumentException: The specified value is not an instance of type 'Edm.Int32'
Parameter name: value

Однако, удалив условный тест, и он отлично работает:

return users.SingleOrDefault(
                user =>
                user.Username == username &&
                user.EncryptedPassword == password &&
                user.StatusID == 1
                );

Любые идеи? Как вы выполняете условное тестирование в EF 4? Разумеется, не разделяются ли строки?

Я использую эти условные тесты снова и снова в Linq to Sql; это действительно странно, почему это не работает в EF 4. Должно быть что-то простое не так, возможно, есть рекомендуемый альтернативный способ делать что-то в EF 4.0.

Спасибо за помощь, ребята,
Graham

Ответ 1

Хорошо, я решил это с помощью комбинации двух вещей.

  • Выполнение простого нулевого теста.
  • Тестирование локальной переменной cast status без метода .Value.

Оба должны быть на месте, иначе он будет продолжать сбой с ошибкой! Было бы неплохо проверить свойство value, но я думаю, что запрос должен быть очень простым - довольно интересно!

return users.SingleOrDefault(
                user =>
                user.Username == username &&
                user.EncryptedPassword == password &&
                (status == null || user.StatusID == (int) status)
                );

Я буду ждать какой-либо лучшей реализации, иначе принимаю мой собственный ответ. Но спасибо за помощь всем.

Ответ 2

Как создать отдельную переменную для !status.HasValue и использовать ее вместо этого в запросе?

Я думаю, проблема здесь в том, что EF пытается передать вашу переменную статуса в качестве параметра в запрос, а затем выполнить логику в самом SQL. Попробуйте проверить, какой SQL создан.

Ответ 3

Альтернативный способ выполнения нулевой проверки в предложении where будет разделять необязательный параметр и применять его только при необходимости.

например.

    var data = users.Where(
        user =>
            user.Username == username &&
            user.EncryptedPassword == password
        );

    if (status.HasValue)
    {
        data = data.Where(user => user.StatusID == status.Value);
    }

    return data.FirstOrDefault();

Я не думаю, что он будет предлагать многое по сравнению с вашим текущим решением, отличным от немного большей удобочитаемости.

Ответ 4

Похоже, вы уже нашли решение...

Однако, просто fyi... у меня нет проблем со следующей строкой в ​​VS 2010

  Nullable<int> status = 0;
  String username = "Alexandre 2";

    var test = _context.Contacts.SingleOrDefault(c => c.FirstName == username && (!status.HasValue || c.ContactID == 1));

Я не получаю никаких ошибок, и объект Contact, который я ожидаю, является возвратом... так что, если что-нибудь, это заставляет меня задаться вопросом, какой тип вашего поля user.StatusID?

Желаем удачи.

Ответ 5

что такое status.HasValue? если статус является полем User, вы должны называть его следующим образом: user.status.HasValue

просто выполните это:

if(status.HasValue)
    return users.SingleOrDefault(
                user =>
                user.Username == username &&
                user.EncryptedPassword == password &&
                user.StatusID == 1
                );

    return users.SingleOrDefault(
                user =>
                user.Username == username &&
                user.EncryptedPassword == password
                );

Ответ 6

Я думаю, вы должны заключить user.StatusID == 1 в дополнительный набор круглых скобок, так как я думаю, что в настоящее время EF пытается применить || операции с status.HasValue и user.StatusId, а затем сравнить результат с 1.

Ответ 7

На первой галансе это выглядит так:

return users.SingleOrDefault(
                user =>
                user.Username == username &&
                user.EncryptedPassword == password &&
                (status == null || user.StatusID == 1)
                );

но когда я смотрю на него больше, я чувствую, что это неправильно, а что?

return users.SingleOrDefault(
    user =>
    user.Username == username &&
    user.EncryptedPassword == password &&
    status != null &&
    user.StatusID == 1)
  );

Какова именно бизнес-логика?