Сортировка связанного ASP.NET GridView по количеству элементов в свойстве навигации Entity Framework - PullRequest
4 голосов
/ 24 ноября 2011

У меня есть страница ASP.NET с элементом управления GridView, связанным с EntityDataSource (см. Упрощенный код ниже). Сетка отображает список элементов Parent и содержит столбец для отображения .Count из Children для этого родителя. Я могу заставить таблицу правильно отображать счетчик, но не могу понять, что использовать для значения asp: TemplateField SortExpression, чтобы можно было установить сортировку для количества детей.

Вот как выглядит мой код (упрощено для ясности) ...

<asp:EntityDataSource ID="edsParentList" runat="server" 
     ConnectionString="name=FooEntities" 
     DefaultContainerName="FooEntities" 
     EnableFlattening="False" 
     EntitySetName="Parents" 
     EntityTypeFilter="Parent"
     Include="Children"
     OrderBy="it.Name"
     Where="(it.Name LIKE '%' + @ParentNameLike + '%')
     >
     <WhereParameters>
         <asp:Parameter Name="ParentNameLike" Type="String" DefaultValue="_" />
     </WhereParameters>
 </asp:EntityDataSource>
 <asp:GridView ID="grdParents" runat="server" 
     AllowPaging="True" 
     AllowSorting="True" 
     AutoGenerateColumns="False" 
     DataSourceID="edsParentList"
     PageSize="20" 
     onpageindexchanged="grdParents_PageIndexChanged" onsorted="grdParents_Sorted" >
     <Columns>
         <asp:TemplateField HeaderText="Name" SortExpression="Name">
             <ItemTemplate>
                 <a href="Parent.aspx?id=<%# Eval("ParentID") %>"><%# Eval("Name") %></a>
             </ItemTemplate>
         </asp:TemplateField>
         <asp:BoundField DataField="BirthDate" HeaderText="Birth Date" 
              DataFormatString="{0:yyyy-MM-dd HH:mm}"
              SortExpression = "BirthDate" />
         <asp:TemplateField HeaderText="Children" SortExpression="Children.Count">
             <ItemTemplate>
                 <asp:Label ID="lblChildCount" runat="server" 
                  Text='<%# Eval("Children.Count") %>'></asp:Label>
             </ItemTemplate>
         </asp:TemplateField>
     </Columns>
 </asp:GridView>

Показывает сетку в порядке. Однако, когда я нажимаю на заголовок столбца «Дети», выдается следующее сообщение:

'Count' не является членом 'Transient.collection [FooEntities.Child (Nullable = True, DefaultValue =)]'. Чтобы извлечь свойство элемента коллекции, используйте подзапрос для перебрать коллекцию.

Мой вопрос: Как включить сортировку по .Count () свойства навигации, которое состоит из коллекции дочерних объектов?

Есть ли способ указать это с помощью SortExpression, или мне нужно разбить страницу на части и выполнить все операции подкачки и сортировки вручную? (Которого я бы предпочел избегать!)

Ответы [ 2 ]

1 голос
/ 01 мая 2012

Я воспроизвел ошибку (в более простом примере) и считаю, что невозможно найти какие-либо SortExpression, которые могли бы выполнить сортировку по количеству детей.

Я видел две важные дополнительные информации:

  • Исключение, которое выдается при нажатии на заголовок столбца: EntitySqlException
  • Последний метод в трассировке стека, который в конечном итоге выдает исключение: EntityDataSourceView.ExecuteSelect(DataSourceSelectArguments arguments)

ExecuteSelect - это abstract метод DataSourceView, который переопределяется различными конкретными элементами управления источником данных для выполнения фактической работы по загрузке данных из хранилища данных. В случае EntityDataSource соответствующим представлением является EntityDataSourceView и из сгенерированного исключения - EntitySqlException - я бы пришел к выводу, что ExecuteSelect строит запрос, используя Entity SQL .

Аргумент DataSourceSelectArguments содержит параметры, определенные в EntityDateSource, а также SortExpression, который, скорее всего, является просто выражением сортировки, которое вы указали в TemplateField. Они используются для составления окончательного запроса в Entity SQL.

Я бы предположил, что SortExpression просто передается как предложение ORDER BY в выражении Entity SQL. Это будет выглядеть так:

ORDER BY Children.Count

Но это недействительный Entity SQL. Вы можете использовать пунктирные пути для ссылки навигации, но вы не можете использовать какие-либо "похожие на LINQ" методы или свойства (например, Count) коллекции навигации в Entity SQL.

Можно написать действительный Entity SQL, отсортированный по количеству детей. Согласно этому примеру (ищите «Упорядочить по связанным объектам» в файле) правильный оператор Entity SQL будет:

"SELECT VALUE p2.p 
 FROM (SELECT p, ANYELEMENT(SELECT VALUE Count(c.ChildId) FROM p.Children AS c)
                 AS childCount
       FROM Parents AS p)
 AS p2
 ORDER BY p2.childCount"

(Это так трудно читать, что я даже не знаю, как сделать отступ в семантически правильном коде).

Я думаю, что эта конструкция ANYELEMENT(SELECT... является «подзапросом», о котором говорит исключение и который он хочет иметь для подсчета элементов дочерней коллекции.

Очевидно, что вы не можете передать p2.childCount в SortExpression без всего подзапроса, который определяет p2.

Мой вывод: нет надежды найти работающую SortExpression для подсчета детей.

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

Почему потребители EntityDataSource и GridView должны сами это выяснить? Вы когда-нибудь видели документированное: " Когда источник данных имеет тип EntityDataSource, SortExpression из TemplateField в GridView должен быть действительным Entity SQL ORDER BY предложением ."Я не сделал. Просто что-то вроде: «SortExpression - это выражение для сортировки».

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

1 голос
/ 30 апреля 2012

С вашей точки зрения, поскольку классы сущностей объявлены как частичные, я бы попытался создать дополнительный файл кода частичных классов для сущности Parent и добавить свойство ChildCount только для чтения.Это свойство будет ссылаться на свойство навигации детей.Я бы тогда отсортировал это.

Здесь я предполагаю, что EntityDataSource может работать с тем, что я буду называть производными свойствами для сущности.Я не проверял это.

...