Почему Reverse() нельзя преобразовать в SQL?

Мое приложение работает под управлением ASP.NET 4.0, которое использует BLToolkti в качестве инструмента ORM.

У меня есть запросное выражение:

var q = db.GetTable<T>()
    .Where(tb=>tb.TeamId==MyTeamId && tb.Season==MySeasonId)
    .OrderByDescending(tb=>tb.Id)
    .Take(20)
    .Reverse()

Попытка преобразовать q.ToList() вызывает следующую ошибку:

Sequence 'Table(TeamBudget).Where(tb => ((tb.TeamId == value(VfmElita.DataLogicLayer.Teams.Team+TeamBudget+‹>c__DisplayClass78).teamId) AndAlso (tb.Season == value(VfmElita.DataLogicLayer. Teams.Team+TeamBudget+‹>c__DisplayClass78).season))).OrderByDescending(tb => Convert(tb.Id)).Take(20).Reverse()' нельзя преобразовать в SQL.

Если я удаляю ".Reverse()" из запрашиваемого объекта, все работает нормально.

По какой причине запрашиваемый объект с .Reverse() не может быть преобразован в SQL? Это ограничение BLToolkit? Есть ли какое-либо решение для этого?

Благодарю вас!


person Budda    schedule 13.08.2014    source источник
comment
Что происходит при использовании .OrderBy(tb => tb.Id) вместо .Reverse()?   -  person user2864740    schedule 13.08.2014
comment
Это так, но проблема в том, что он также вводит новые псевдонимы для полей, а сопоставление BLToolkit ORM больше не может сопоставлять столбцы sql с полями объекта. Но спасибо за идею   -  person Budda    schedule 13.08.2014


Ответы (1)


Совершенно ясно, что другие методы LINQ преобразуют в (where, order by, top(20)), но во что преобразуется Reverse()? Я не могу придумать оператор SQL, который имитировал бы такое поведение, и когда вы запрашиваете базу данных, ваш оператор LINQ должен в конечном итоге разрешаться в допустимый SQL.

Возможно, это не то, к чему вы стремитесь, но один из вариантов — сначала выполнить запрос, используя ToList(), затем применить Reverse():

var q = db.GetTable<T>()
          .Where(tb => tb.TeamId == MyTeamId && tb.Season == MySeasonId)
          .OrderByDescending(tb => tb.Id)
          .Take(20)
          .ToList()
          .Reverse();

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

var totalRecords = db.GetTable<T>()
                     .Count(tb => tb.TeamId == MyTeamId && tb.Season == MySeasonId);

var q = db.GetTable<T>()
          .Where(tb => tb.TeamId == MyTeamId && tb.Season == MySeasonId)
          .Order(tb => tb.Id)
          .Skip(totalRecords)
          .Take(20);
person Grant Winney    schedule 13.08.2014
comment
Обратный порядок по убыванию по эквиваленту ROW_NUMBER (даже без знания начальный упорядоченный столбец) во внешнем выборе производной таблицы вполне возможен. Это тривиально в SQL Server и возможно в MySQL; насчет других продавцов не уверен. - person user2864740; 13.08.2014
comment
Кроме того, при правильных уровнях изоляции транзакций (и использовании) не должно быть проблем со вторым подходом и атомарностью/непротиворечивостью для надлежащего поставщика ACID. (В EF/L2S я бы просто использовал TransactionScope и прекратил работу.) - person user2864740; 13.08.2014