Почему EF выбрасывает "NotSupportedException: Метод 'First' может использоваться только как конечная операция запроса"

int[] ids1 = { 1, 2, 3 };
int[] ids2 = { 1, 5, 6 };

var result = from a in ids1
             where a == ids2.First()
             select a;  
foreach (var item in result) ; //ok


var employees = from c in context.Employees.
                where c.EmployeeID == ids1.First() 
                select c;   
foreach (var item in employees); // NotSupportedException

При попытке вызвать ids1.First в запросе Linq-to-Entities, я получаю исключение System.NotSupportedException: Метод 'First' может быть использован только в качестве конечной операции запроса. Рассмотрите возможность использования метода 'FirstOrDefault' в этом экземпляре вместо этого.

a) Я не понимаю, почему First может использоваться только как финальная операция запроса, так как в нашем примере First вызывается на IEnumerable<> ( ids1.First() ), а не на IQueryable<>. Другими словами, First вызывается в запросе Linq-to-Objects, а не в запросе Linq-to-Entities?!

б) В любом случае, почему First должен использоваться как заключительная операция запроса, а FirstOrDefault не должен быть заключительной операцией запроса?

Спасибо


ОТВЕТ:

Что касается разницы между First() и FirstOrDefault() - я не знаю. знаю. Вы пробовали, и работает ли это?

Да, работает

Нет, First() вызывается в запросе LINQ to Entities. Ваше где будет преобразовано в: Where(c => c.EmployeeID == ids1.First())

a) Теперь я немного запутался. Я понимаю, что ids1.First по сути вызывается внутри запроса Linq-to-Entities, но факт остается фактом: First вызывается на IEnumerable<>, и как таковой First вызывается внутри запроса Linq-to-Objects, а этот запрос Linq-to-Object в свою очередь вызывается внутри запроса Linq-To-entities - по крайней мере так я это понимаю?!

Или вы подразумеваете, что First как-то вызывается на IQeryable<>?

б) Я понимаю, что (c => c.EmployeeID == ids1.First()) будет преобразован в дерево выражений, но почему ids1.First() не выполняется до преобразования?

c) В любом случае, когда преобразование в дерево выражений произойдет, я предполагаю, что когда sql-провайдер получит дерево выражений нашего where предложения и попытается преобразовать его в Sql команду, у этого Sql-провайдера не хватит "мощности" выполнить ids1.First, чтобы получить результат обратно (который он затем поместит в Sql запрос), и отсюда исключение?!


ВТОРОЙ ОТВЕТ:

a) Я все еще не понимаю, почему ids1.First не выполняется до преобразования в дерево выражений?! А именно, при следующем пункте

Where(c => c.EmployeeID == 2+3) 

выражение 2+3 выполняется до того, как этот пункт Where преобразуется в дерево выражений! А ids.First - это тоже своего рода выражение, так что я ожидал бы аналогичного поведения!

b) Извините за повторение, но меня очень беспокоит, действительно ли мое предположение - что First вызывается внутри запроса Linq-to-Objects, а этот запрос Linq-to-Object в свою очередь вызывается внутри запроса Linq-To-entities - верно?!

c) Возможно, я неправильно понял ваш пост, но вы подразумеваете, что большинство других операторов Linq-to-Object могут быть вызваны на IEnumerable<> E, даже если E содержится в запросе Linq-to-Entities ?

7
задан user702769 18 October 2011 в 19:05
поделиться