LINQ To Entities не распознает метод Last. В самом деле?
В этом запросе:
public static IEnumerable<IServerOnlineCharacter> GetUpdated()
{
var context = DataContext.GetDataContext();
return context.ServerOnlineCharacters
.OrderBy(p => p.ServerStatus.ServerDateTime)
.GroupBy(p => p.RawName)
.Select(p => p.Last());
}
Мне пришлось переключить его на это, чтобы он работал
public static IEnumerable<IServerOnlineCharacter> GetUpdated()
{
var context = DataContext.GetDataContext();
return context.ServerOnlineCharacters
.OrderByDescending(p => p.ServerStatus.ServerDateTime)
.GroupBy(p => p.RawName)
.Select(p => p.FirstOrDefault());
}
Я даже не мог использовать p.First()
, чтобы отразить первый запрос.
Почему существуют такие основные ограничения в том, что в противном случае такая надежная система ORM?
Ответы
Ответ 1
Это ограничение сводится к тому, что в конечном итоге он должен перевести этот запрос на SQL, а SQL имеет SELECT TOP
(в T-SQL), но не SELECT BOTTOM
(нет такой вещи).
Существует простой способ, но просто порядок убывания, а затем выполните First()
, что и было.
EDIT:
Другие провайдеры, возможно, будут иметь разные реализации SELECT TOP 1
, в Oracle это, вероятно, будет больше похоже на WHERE ROWNUM = 1
EDIT:
Еще одна менее эффективная альтернатива - Я НЕ рекомендую это! - вызов .ToList()
для ваших данных до .Last()
, который немедленно выполнит созданное выражение LINQ To Entities Expression к этой точке, а затем ваш .Last() будет работать, потому что в этот момент .Last()
эффективно выполняется в контексте выражения LINQ to Objects. (И, как вы указали, это может привести к тысячам записей и ненужным нагрузкам на материализующие объекты, которые никогда не будут использоваться)
Опять же, я бы не рекомендовал делать эту секунду, но это помогает проиллюстрировать разницу между тем, где и когда выполняется выражение LINQ.
Ответ 2
Вместо Last()
, попробуйте следующее:
model.OrderByDescending(o => o.Id).FirstOrDefault();
Ответ 3
Заменить Last()
селектором Linq OrderByDescending(x => x.ID).Take(1).Single()
Что-то вроде этого будет работать, если вы предпочитаете делать это в Linq:
public static IEnumerable<IServerOnlineCharacter> GetUpdated()
{
var context = DataContext.GetDataContext();
return context.ServerOnlineCharacters.OrderBy(p => p.ServerStatus.ServerDateTime).GroupBy(p => p.RawName).Select(p => p.OrderByDescending(x => x.Id).Take(1).Single());
}
Ответ 4
Еще один способ получить последний элемент без OrderByDescending и загрузить все объекты:
dbSet
.Where(f => f.Id == dbSet.Max(f2 => f2.Id))
.FirstOrDefault();
Ответ 5
Это потому, что LINQ to Entities (и базы данных в целом) не поддерживает все методы LINQ (подробности см. Здесь: http://msdn.microsoft.com/en-us/library/bb738550.aspx).
Здесь вам нужно упорядочить данные таким образом, чтобы "последняя" запись стала "первой", а затем вы можете использовать FirstOrDefault. Обратите внимание, что базы данных обычно не имеют таких понятий, как "первый" и "последний", это не означает, что последняя добавленная запись будет "последней" в таблице.
Этот метод может решить вашу проблему
db.databaseTable.OrderByDescending(obj => obj.Id).FirstOrDefault();
Ответ 6
Добавление единственной функции AsEnumerable()
до того, как функция Select сработало для меня.
Пример:
return context.ServerOnlineCharacters
.OrderByDescending(p => p.ServerStatus.ServerDateTime)
.GroupBy(p => p.RawName).AsEnumerable()
.Select(p => p.FirstOrDefault());
Ссылка: https://www.codeproject.com/info/1005274/LINQ-to-Entities-does-not-recognize-the-method-Sys