Linq возвращает список или отдельный объект

У меня есть запрос Linq to Entities, подобный этому:

var results = from r in entities.MachineRevision
              where r.Machine.IdMachine == pIdMachine
                 && r.Category == (int)pCategory
              select r;

Обычно я использую приведенный ниже код, чтобы проверить, возвращаются ли какие-либо результаты:

if (results.Count() > 0)
{
    return new oMachineRevision(results.First().IdMachineRevision);
}

Однако я получаю NotSupportedException в условии if.

Сообщение об ошибке: Невозможно создать постоянное значение типа «Тип закрытия». В этом контексте поддерживаются только примитивные типы (такие как Int32, String и Guid).

Обратите внимание, что pCategory - это тип Enum.


person Nelson Reis    schedule 30.12.2008    source источник


Ответы (8)


ИЗМЕНИТЬ: на основании вашего обновления ошибка может быть связана с перечислением в вашем классе сущности. См. Эту запись в блоге для получения дополнительной информации и работы -вокруг. Я оставляю свой исходный ответ как улучшение синтаксиса вашего запроса.

Попробуйте выбрать первую сущность в самом запросе с помощью FirstOrDefault, а затем проверьте, является ли результат нулевым.

int compareCategory = (int)pCategory; // just a guess
var result = (from r in entities.MachineRevision
              where r.Machine.IdMachine == pIdMachine
                 && r.Category == compareCategory
              select r).FirstOrDefault();

if (result != null)
{
     return new oMachineRevision(result.IdMachineRevision);
}
person tvanfosson    schedule 30.12.2008
comment
По-прежнему не работает, потому что мы пытаемся выполнить метод FirstOrDefault () для объекта сущности (который возвращается оператором linq), а не IEnumerable. - person Nelson Reis; 30.12.2008
comment
Select всегда возвращает IEnumerable, см. Документацию здесь msdn.microsoft.com/en-us /library/bb548891.aspx. Вы уверены, что пример точно такой же, как и ваш код? - person tvanfosson; 30.12.2008
comment
Моя ошибка, прошу прощения за это. Чтобы упростить код, я удалил перечисление, точно так же, как tvanfosson заметил сообщение об ошибке, которое я получал. Спасибо всем и извиняюсь за то, что ввёл вас в заблуждение. - person Nelson Reis; 30.12.2008

Почему бы просто не использовать вместо этого FirstOrDefault () и проверить значение null? Я не вижу пользы в запросе подсчета и последующем выборе первого элемента.

person Jon Skeet    schedule 30.12.2008
comment
Я понимаю вашу точку зрения. Однако, если я использую FirstOrDefault (), я все равно получаю это NotSupportedException, потому что я пытаюсь выполнить этот метод для объекта сущности (то, что возвращается оператором Linq), а не для IEnumerable. - person Nelson Reis; 30.12.2008

В стандартной реализации linq операторы select и where сопоставляются с методами, возвращающими IEnumerable или IQueryable. Таким образом, стандартные методы linq при использовании всегда должны возвращать IEnumerable из вашего запроса, а не отдельный объект.

Но методы linq, которые являются кандидатами на роль операторов linq, не ограничиваются методами, возвращающими IEnumerables, можно выбрать любой метод, возвращающий что-либо.

Если у вас есть методы экземпляра с именами «Выбрать» и «Где», которые возвращают один объект или методы расширения, специфичные для вашего класса, и возвращают один объект, они будут использоваться вместо стандартных методов linq.

Я предполагаю, что метод «Выбрать» или «Где», определенный в вашем классе, заставляет linq возвращать единственное значение вместо IEnumerable<T>.

person Pop Catalin    schedule 30.12.2008

Я не знал, что в зависимости от результата запроса будут созданы разные анонимные объекты. Я думаю, они просто хотели, чтобы результаты были типа IEnumerable.

Как насчет использования foreach?

var results = from r in entities.MachineRevision
              where r.Machine.IdMachine == pIdMachine
                 && r.Category == pCategory
              select r;

foreach( var r in results )
{
    yield return new oMachineRevision( r.IdMachineRevision );
}
person Trap    schedule 30.12.2008

Это касается и всех неявных типов. Должен признаться, я все время забываю об этом, и вот как я наткнулся на этот пост.

если у вас есть

class ClassA {
               ...

               private string value;

               ...

               public static implicit operator string(ClassA value)
               {
                    return value.ToString();
               } 

              ...
}

вам нужно явно преобразовать класс в строку для сравнения.

так что я обычно делаю это

    var myClassAStr = myClassA.ToString();

    var x = (from a in entites where a.ValToCompare == myClassAStr select a).first();

// do stuff with x
    ...
person cmon_stoke    schedule 29.11.2011
comment
на самом деле я обычно использую a.ValToCompare.Equals (myClassAstr) - person cmon_stoke; 29.11.2011

попробуйте использовать

IENumerable<MachineRevision> results = from r in entities.MachineRevision
...

вместо.

Я думаю, что это var, который вызывает вашу проблему.

person NikolaiDante    schedule 30.12.2008

Редактировать:

Прочтите сообщение об ошибке. «Невозможно создать постоянное значение типа 'Closure type'. В этом контексте поддерживаются только примитивные типы ('такие как Int32, String и Guid')».

Одно из этих сравнений - с типом, который не является int, string или guid. Я предполагаю категорию.

r.Machine.IdMachine == pIdMachine && r.Category == pCategory

Интересно, что LinqToSql позволяет такую ​​конструкцию. Не знаю, почему LinqToEntities не поддерживает это.

person Amy B    schedule 30.12.2008

Я думаю, вы также можете выбрать нужный элемент другим, более простым способом, используя лямбда-выражения.

var result = entities.MachineRevision
                 .Where(x => x.Machine.IdMachine == pIdMachine)
                 .Where(y => y.Category == (int)pCategory)
                 .FirstOrDefault();

if (result != null)
{
     return new oMachineRevision(result.IdMachineRevision);
}

а затем продолжайте, как обычно

person dan richardson    schedule 16.06.2009
comment
Не работает, потому что .Where (y = ›y.Category == (int) pCategory) выдает ошибку. Перед запросом вам нужно выполнить приведение Enum. var iCategory = (int) pCategory; а затем просто используйте iCategory в самом запросе. - person derSteve; 07.09.2009