2013-03-14 5 views
2

Я пытаюсь использовать Expression внутри LINQSelect. Вот пример моего кодаLINQ Выберите выражение IEnumerable

Expression<Func<user, string>> expr = d => d.user.username; 
Message.Select(b => new { name = b.user.Select(expr) }); 

сообщение имеет тип IEnumerable, во время выполнения я получаю следующее сообщение об ошибке: The exception message is ''System.Collections.Generic.List<W.Models.user>' does not contain a definition for 'Select'

Как это исправить?

ответ

5

Похоже, что вам не хватает using System.Linq; в верхней части вашего кода. Обратите внимание, однако, что List<T> является LINQ-to-Objects; потеря Expression:

Func<user, string> expr = d => d.user.username; 
Message.Select(b => new { name = b.user.Select(expr) }); 

Заключительная мысль; в то время как сообщение о System.Collections.Generic.List<W.Models.user> предлагает список, ваш код (b.User.Select/Message.Select) предлагает отдельные объекты. Это смущает.

+0

Я использую System.Linq и System.Linq.Expressions –

+0

@TobiasOlofsson вы видели редактирование об удалении 'Expression'? Однако я считаю, что ваш лучший выбор - уменьшить это до минимального *** запускаемого *** примера. Скорее всего, вы обнаружите проблему при ее уменьшении, но если вы не можете: люди смогут ее воспроизвести и исправить. –

+0

В БД сообщение таблицы имеет отношение к отношению «один ко многим» к пользователю, я пытаюсь выбрать всех пользователей для сообщения из запроса IEnumerable , содержащего это сообщение. Model.user - это код сначала EF. –

0

Пожалуйста, взгляните на Why would you use Expression<Func<T>> rather than Func<T>?.

В принятом ответе описывается, что Func<T> является делегатом метода, который возвращает T. Expression<Func<T>> Однако на самом деле это описание того, как этот делегат может быть оценен. Вы можете, например, compile an expression в фактический делегат:

Expression<Func<int, bool>> expr = i => i < 5; 
Func<int, bool> deleg = expr.Compile(); 
Console.WriteLine("deleg(4) = {0}", deleg(4)); 

Вы можете даже написать:

Console.WriteLine("deleg(4) = {0}", expr.Compile()(4)); 

Так что, если вам действительно нужно выражение вам нужно собрать его в фактический делегат иным образом использовать делегат первое место.

(BTW:. Ваш пример кода не скомпилируется, так как нет Select метод для List<user>, который принимает выражение, а также d => d.user.username, вероятно, неправильно С d является user она должна быть d => d.username).

Однако linq для сущностей не поддерживает вызовы делегатов. Поэтому вы должны переключиться на LINQ к объектам путем добавления AsEnumerable():

Expression<Func<user, string>> expr = d => d.username; 
Func<user, string> func = expr.Compile(); 

var result = context.Message.AsEnumerable() 
          .Select(b => new { name = b.user.Select(func) }); 

Использование LINQ для лиц, для доступа к данным, простой порядок, фильтрации и т.д. Таким образом, он может оптимизировать запросы к базе данных, но затем включите к linq к объектам, если вам нужно больше.

PS: Лямбда d => d.username скомпилирована в делегат. Если вы явно помещаете его в выражение b.user.Select(u => u.username), он будет работать нормально, потому что теперь он также компилируется в выражение, которое linq для объектов может обрабатывать без вызова делегата.

+0

Сообщение об исключении: '' System.Collections.Generic.List 'не содержит определения для' Select ' –

+0

@TobiasOlofsson: 'b.user' в вашей лямбда - это« Список »и вы передаете выражение методу 'Select'. Нет метода 'Select', который принимает выражение (если вы не объявили метод расширения для' List <> '). Так что это невозможно даже скомпилировать. Но даже когда вы передаете «Func» linq для сущностей, вы не сработаете, потому что он не сможет выполнить делегат (как я действительно протестировал: «Invoke» не поддерживается EF »). – pescolino