我有一个ASP.NET页面,其中GridView控件绑定到EntityDataSource(请参阅下面的简化代码(。该网格显示Parent
项的列表,并包含一列以显示此父项的Children
的.Count。我可以让网格正确地显示计数,但我不知道如何使用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>
这将精细显示网格。然而,当我点击Children列的标题时,会抛出以下错误:
"Count"不是的成员"Transient.collection[FooEntities.Child(Nullable=True,DefaultValue=(]"。若要提取集合元素的属性,请使用子查询对集合进行迭代。
我的问题是:如何对由子对象集合组成的导航属性的.Count((启用排序
有没有一种方法可以用SortExpression指定这一点,或者我必须分解并手动进行所有的分页和排序?(我显然更喜欢避免!(
在您的位置上,由于实体类被声明为分部类,我会尝试为Parent实体创建一个补充的分部类代码文件,并添加一个ChildCount只读属性。此属性将引用Children导航属性。然后我会对此进行分类。
在这里,我假设EntityDataSource可以处理实体上的派生属性。我还没有对此进行测试。
我已经重现了错误(在一个更简单的例子中(,我认为不可能找到任何对儿童计数执行排序的SortExpression
。
我看到了两个重要的附加信息:
- 单击列标题时引发的异常是
EntitySqlException
- 堆栈跟踪中最后抛出异常的方法是
EntityDataSourceView.ExecuteSelect(DataSourceSelectArguments arguments)
ExecuteSelect是DataSourceView
的abstract
方法,由各种特定的数据源控件覆盖,以执行从数据存储加载数据的实际工作。在EntityDataSource
的情况下,对应的视图是EntityDataSourceView
,从抛出的异常(EntitySqlException
-我会得出结论,ExecuteSelect
使用实体SQL构建查询。
参数DataSourceSelectArguments
包含在EntityDateSource
中定义的参数,还有一个SortExpression
,它很可能只是您在TemplateField
上指定的排序表达式。这些用于组成实体SQL中的最终查询。
我假设SortExpression
只是作为实体SQL语句中的ORDER BY
子句传递的。这看起来像:
ORDER BY Children.Count
但这是无效的实体SQL。您可以使用虚线路径作为导航引用,但不能在Entity SQL中使用导航集合的任何"类似LINQ"的方法或属性(如Count
(。
可以编写一个有效的实体SQL,按照子级计数进行排序。根据这个例子(在文件中搜索"按相关实体排序"(,正确的实体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
的整个子查询,就无法将p2.childCount
传递到SortExpression
中。
我的结论是:没有希望为儿童计数找到一个有效的SortExpression
。
也许有一种方法不使用SortExpression
——例如,在标头上捕获一个点击事件,然后在事件处理程序中手动构建完整的查询,但我真的不知道这是否可能以及如何可能。
为什么EntityDataSource
和GridView
的消费者必须自己解决这个问题?您是否看到以下文档:">当数据源的类型为EntityDataSource
时,GridView
中TemplateField
的SortExpression
必须是有效的实体SQLORDER BY
子句。"我没有。就像:"SortExpression
是一个排序表达式。">
不幸的是,由于没有明确说明SortExpression
会发生什么,正确的语法是什么,支持或不支持什么类型的表达式,所以这个答案与其说是答案,不如说是猜测。