LINQ - Как мне упорядочить свои (сложные) результаты? - PullRequest
5 голосов
/ 10 сентября 2011

У меня есть запрос LINQ, который построен по частям, например так:

var initialQuery = from item in MyContext where xxx == yyy select item;    
var furtherQuery = from item in initialQuery where bla == foo select new { some stuff };

// more code here...

// eventually:
var yetAnotherQuery = (from item in furtherQuery ...)
                      .OrderBy(my_condition);

// As far as I know, the following query should still maintain the order of the previous one
// see: /765432/garantiruytsya-li-podzaprosy-v-linqtosql-v-tom-zhe-poryadke-chto-i-ih-roditel

var stillAnotherQuery = (from item in yetAnotherQuery
                         select item.data_I_care_about)
                         .Distinct();

// And finally...
var finalQuery = stillAnotherQuery.Skip(PageIndex).Take(PageSize);

Но я получаю исключение, когда вызывается Skip(), говоря, что запрос не упорядочен!Очевидно, что то, что указано в моем комментарии к коду выше и вопрос , на который есть ссылка *1006*, не совсем верно.Фактически другой ответ SO указывает на то, что сохранение этого порядка не гарантируется.

Кто-нибудь знает хороший способ сделать то, что я пытаюсь выполнить?

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

Я видел несколько другие SO вопросы пытаются получить ROW_NUMBER там, но, насколько я видел, они все клиентские.

Мне кажется,нарисовал себя в углу.Кто-нибудь знает (LINQ-friendly) выход?


ОБНОВЛЕНИЕ


Некоторые предлагали мне сделать Distinct() до OrderBy().Я полагаю, что это дало бы мне другие результаты.

Представьте, что у меня есть эта таблица данных

myRank | myData
-------+--------
   3   |    A
   1   |    B
   2   |    A

Предположим, я заказываю по myRank, а данные, которые меня интересуют, - myDataи представьте, что мой оригинальный код был таким:

var query = from item in MyTable
            select item;

query = query.OrderBy(item => item.myRank);

var derivedQuery = from item in query        // Note: we throw away myRank
                   select item.myData;

derivedQuery = derivedQuery.Distinct();

Если я поменяю местами порядок OrderBy() и Distinct(), я получу разные результаты.Я не хочу, чтобы myRank был включен в Distinct().

Извините, это часть гораздо более масштабного процесса, поэтому трудно разобраться во всех подробностях этого вопроса.

Но, надеюсь, это имеет смысл?

Ответы [ 4 ]

2 голосов
/ 10 сентября 2011

Из-за его реализации, Distinct не гарантирует сохранение порядка. Вы не можете запустить Skip на его выходе из-за этого, и дажеесли бы вы могли, вы бы не могли полагаться на поведение Skip.

Вам нужно будет запустить OrderBy после того, как вы запустите Distinct.Я не вижу способа сделать это с помощью одного звонка на OrderBy, учитывая то, что вы пытаетесь сделать.yetAnotherQuery и stillAnotherQuery содержат разные элементы, поэтому их нужно будет отсортировать по отдельности.

На мой взгляд, у вас есть два варианта.Вы можете либо совершить одну поездку в базу данных для yetAnotherQuery, а затем запустить Distinct и OrderBy локально для stillAnotherQuery:

var yetAnotherQuery = (from item in furtherQuery ...)
                      .OrderBy(my_condition);

var stillAnotherQuery = (from item in yetAnotherQuery ...)
                        .Distinct()
                        .OrderBy(my_condition);

var finalQuery = stillAnotherQuery.Skip(PageIndex).Take(PageSize);

... или вы можете сделать две поездки в базу данных, но выполняйте всю сортировку и фильтрацию на сервере базы данных:

var yaq_UnSorted = (from item in furtherQuery ...);

var yetAnotherQuery = yaq_UnSorted
                      .OrderBy(my_condition);

var stillAnotherQuery = (from item in yaq_UnSorted ...)
                        .Distinct()
                        .OrderBy(my_condition);

var finalQuery = stillAnotherQuery.Skip(PageIndex).Take(PageSize);

Какое решение лучше для вас, будет зависеть от ваших приоритетов.Первый из них уменьшит количество обращений к вашей БД и объем передаваемых данных, но он также будет использовать больше ресурсов на сервере приложений.

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

2 голосов
/ 10 сентября 2011

Проблема не в том, что элементы больше не упорядочены.

Скорее проблема в том, что Distinct () возвращает IQueryable<T>, тогда как OrderBy () возвращает IOrderedQueryable<TSource>, что (очевидно) требуетсячтобы пейджинг работал с EF

Замена шагов Distinct () и OrderBy () должна исправить ситуацию

Edit

Я предлагаю что-то вродеthis:

var query = from item in MyTable
        select item;

query = query.GroupBy(item => item.myData, item => item.myRank);
var derivedQuery = query.OrderBy(group => group.Min())
                        .Select(group.Key);

Уточнение:

  • группировка по приведет к тому, что ключи dinstinct (myData) в любом случае
  • будут отсортированы по Min () из myRank perГруппа будет выполнять тот же порядок, что и сортировка (возрастание) по myRank, сначала , а затем , выполняя Distinc ()
1 голос
/ 10 сентября 2011

Работает ли метод OrderBy после Distinct метода?

Проблема в том, что Distinct не сохраняет порядок.

Ссылка: http://programminglinq.com/blogs/marcorusso/archive/2008/07/20/use-of-distinct-and-orderby-in-linq.aspx

Обновление

Теперь я вижу проблему.Я думаю, вам нужно попробовать использовать GroupBy вместо Distinct.

Примерно так:

var query = MyTable
    .OrderBy(item => item.myRank)
    .GroupBy(item => item.myData)
    .Select(grouping => grouping.First().myData);
0 голосов
/ 10 сентября 2011

Я не думаю, что проблема в том, что Distinct() меняет порядок - но он возвращает "нормальный" IQueryable<T> вместо IOrderedQueryable<T>, который, по-видимому, необходим для реализации Linq to Entities Skip.

Одним из решений может быть изменение порядка методов OrderBy() и Distinct(), так что сначала вы делаете Distinct(), затем применяете порядок позже, а затем используете Skip().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...