Ограничить ObjectSet связанной сущностью и отсортировать по имени динамического столбца.

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

Parent.                                             // EntityObject
Children.                                           // EntityCollection
Where(c => c.Gender == 'm').                        // IEnumerable
OrderBy(columnName, ListSortDirection.Ascending).   // -- not available --
Skip(pages * pageSize).Take(pageSize);

IEnumerable.OrderBy(string columnName) не существует. Оглядываясь вокруг, чтобы выполнить «сортировку по имени динамического столбца», я начал с этого отлично выглядящего решения: Как создать дерево выражений для сортировки во время выполнения? , но это работает с IQueryable

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

Repository.                                         // Repository
Children.                                           // ObjectSet
Where(c => c.Parent == Parent && c.Gender == 'm').  // ObjectQuery, runtime error
OrderBy(columnName, ListSortDirection.Ascending).   // IOrderedQueryable
Skip(pages * pageSize).Take(pageSize);

ObjectSet и ObjectQuery реализуют OrderBy(string columnName), и этот код компилируется, но выдает ошибку:

Не удалось создать постоянное значение типа DataModel.Parent. В этом контексте поддерживаются только примитивные типы («такие как Int32, String и Guid»).

Конечно, я могу получить идентификатор родителя, но Child.ParentReference также не является примитивным типом.

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

изменить: притвориться, что я http://en.wikipedia.org/wiki/Quiverfull , и нужно разбить на страницы моих детей. :) edit2: разъяснил мою необходимость запрашивать имя динамического столбца.


person shannon    schedule 09.08.2012    source источник


Ответы (3)


var parents = db.Parents; // Do whatever you need to get your unsorted collection from EF here.

if (sortBy == "Gender")
{
    parents = parents.OrderBy(p => p.Gender);
}
else if (sortBy == "FirstName")
{
    parents = parents.OrderBy(p => p.FirstName);
}

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

Редактировать: убрал чушь о PredicateBuilder, я пошел не в ту сторону, когда начал печатать этот ответ, и забыл убрать старые вещи.

person Gromer    schedule 09.08.2012
comment
+1 Спасибо за ссылку, но разве .Invoke в PredicateBuilder не извлечет запись (даже те, которые я пропущу())? Кроме того, я как раз находился в процессе кодирования коммутатора. Преимущество заключается в большей проверке во время компиляции. Но вместо этого я надеялся прослабить строку кода. - person shannon; 10.08.2012
comment
Кроме того, оператор switch по-прежнему имеет проблему производительности проводов при сортировке IEnumerable. - person shannon; 10.08.2012
comment
Я думаю, что я что-то упустил в вашем вопросе? Вы просто пытаетесь динамически сортировать свои данные, верно? Если да, то то, что я предложил, сделает именно это. - person Gromer; 10.08.2012
comment
Я также могу упорядочить его динамически, просто вызвав IEnumerable.AsQueryable.OrderBy(string) без блока переключателей, но это также вызовет весь набор записей по сети. Проблема в том, что необходимость запрашивать родительское отношение приводит к IEnumerable. Я попытался уточнить в своем первоначальном вопросе. - person shannon; 10.08.2012

Попробуйте заменить ваш OrderBy

OrderBy("age", ListSortDirection.Ascending).

с участием

OrderBy(x => x.Age).

также Где

Where(c => c.Parent == Parent && c.Gender = 'm').

должен прочесть

Where(c => c.Parent == Parent && c.Gender == 'm').
person Daniel Elliott    schedule 09.08.2012
comment
Спасибо. К сожалению, под выбором имени столбца во время выполнения я имел в виду такое, которое я бы использовал в ответ на щелчок по заголовку столбца пользовательского интерфейса. Я обновил свой пример, чтобы уточнить. Кроме того, спасибо, что заметили опечатку предиката в моем первом примере. Фиксированный! - person shannon; 10.08.2012

Итак, у меня было несколько проблем, упомянутых в заголовке вопроса.

Сортировка по выбираемому во время выполнения или динамическому имени столбца требовала некоторого построения выражения. Я использовал популярный метод расширения @Slace здесь.

Для этого требовался IQueryable. IQueryable работает для меня, потому что каждый раз, когда я случайно преобразовывал свой запрос в перечисляемый, я, конечно же, возвращал все результаты обратно по сети перед пейджингом, чего я пытался избежать. Но мне по-прежнему нужен был способ получить IQueryable для результатов с отношением к объекту, который у меня уже был.

Это было что-то простое, которое я упустил из виду, просто присоединение к Entity.Id работало и не приводило к избыточным объединениям в источнике данных. Не такой объектно-ориентированный, как я ожидал от EF, но сойдет.

Repository.                                         // Repository
Children.                                           // ObjectSet
Where(c => c.Parent.Id == Parent.Id).               // ObjectQuery, works fine
OrderBy(columnName, ListSortDirection.Ascending).   // IOrderedQueryable
Skip(pages * pageSize).Take(pageSize);              // Only transfers 1 page
person shannon    schedule 13.08.2012