Entity Framework技术系列之6:数据绑定

前言

ASP.NET针对各种数据访问技术,均提供了数据源控件,以实现在页面对数据进行直接绑定。下图是ASP.NET中数据源控件架构图:

 

1 ASP.NET数据源控件架构图

由上图可见,针对Entity Framework的实体数据模型,ASP.NET提供了EntityDataSource数据源控件,在ASP.NET页面绑定实体数据。通过与ASP.NET的其他数据绑定控件进行配合,你甚至可以不用在后台写任何代码,就可以轻松实现实体数据的CRUD功能。同时,该数据源控件还可以加载关联对象数据,通过它可以实现丰富的页面功能。

本文接下来就在上一篇文章中使用的实体数据模型的基础上,实现一个包含查询、添加、修改和删除的用户信息列表页面和一个显示、添加和修改用户详细信息的表单页面,展示EntityDataSource控件如何应用于常见的ASP.NET WebForm应用场景中。

 

列表

在列表页面中,我将实现用户及其详细信息实体数据的列表显式,以及根据输入条件进行模糊查询筛选,并支持在列表中添加、修改和删除用户实体数据。

一、列表显式

首先在页面中放入一个EntityDataSource控件(可以通过工具箱拖拽到页面,也可以在页面的代码视图中手动编码,后同),并设置其相关属性:

1 <asp:EntityDataSource ID="edsUsers" runat="server" ConnectionString="name=Membership" DefaultContainerName="Membership" EntitySetName="Users" Include="UserDetail" OrderBy="it.Account">
2 </asp:EntityDataSource>

由于需要在列表中展示用户详细信息,所以这里需要显式指定Include属性加载UserDetail实体数据。注意,EntityDataSource不支持延迟加载,需要显式指定需要的关联实体对象,否则将不会加载,这与通过实体上下文环境获取实体数据时的情况不太一样。

ASP.NET页面列表数据绑定控件有很多选择,如DataGrid、GridView、Repeater、ListView等。本文选择ListView作为列表数据绑定控件。在页面中放入一个ListView控件,并设置其相关属性和模板内容:

 1 <asp:ListView ID="lvUsers" runat="server" DataSourceID="edsUsers" >
 2     <LayoutTemplate>
 3         <table border="1" width="800">
 4             <thead>
 5                 <tr>
 6                     <th>帐号</th>
 7                     <th width="200">姓名</th>
 8                     <th width="60">性别</th>
 9                     <th width="120">生日</th>
10                     <th width="150">操作</th>
11                 </tr>
12             </thead>
13             <tbody>
14                 <tr id="itemPlaceholder" runat="server"></tr>
15             </tbody>
16         </table>
17         <uc:Pager ID="Pager1" runat="server" />
18     </LayoutTemplate>
19     <ItemTemplate>
20         <tr>
21             <td><a href='Form.aspx?ID=<%# Eval("ID") %>' target="_blank"><%# Eval("Account") %></a></td>
22             <td><%# Eval("UserDetail.Name") %></td>
23             <td><%# Eval("UserDetail.Sex") %></td>
24             <td><%# Eval("UserDetail.Birthday", "{0:yyyy-MM-dd}")%></td>
25             <td></td>
26         </tr>
27     </ItemTemplate>
28     <EmptyDataTemplate>
29         没有符合条件的数据
30     </EmptyDataTemplate>
31 </asp:ListView>

在布局上这里用了一点小技巧,帐号列没有设置宽度,这样可以根据父级标签元素的宽度来自适应。

Pager是对ASP.NET的DataPager控件进行简单封装的用户控件。ListView控件搭配DataPager控件可以实现数据库层的分页查询。Pager用户控件主要代码如下:

 1 <div id="pager">
 2     <asp:DataPager ID="DataPager" runat="server" PageSize="20">
 3         <Fields>
 4             <asp:NextPreviousPagerField ButtonType="Image" ButtonCssClass="ImageButton-Pager" ShowFirstPageButton="true" ShowNextPageButton="false"
 5                 ShowPreviousPageButton="true" ShowLastPageButton="false" FirstPageImageUrl="~/Images/icon_first_16x16.png"
 6                 PreviousPageImageUrl="~/Images/icon_previous_16x16.png" RenderNonBreakingSpacesBetweenControls="False" />
 7             <asp:NumericPagerField ButtonCount="6" CurrentPageLabelCssClass="LinkButton-Pager-Current" NumericButtonCssClass="LinkButton-Pager" />
 8             <asp:NextPreviousPagerField ButtonType="Image" ButtonCssClass="ImageButton-Pager" ShowFirstPageButton="false" ShowNextPageButton="true"
 9                 ShowPreviousPageButton="false" ShowLastPageButton="true" LastPageImageUrl="~/Images/icon_last_16x16.png"
10                 NextPageImageUrl="~/Images/icon_next_16x16.png" RenderNonBreakingSpacesBetweenControls="False" />
11             <asp:TemplatePagerField>
12                 <PagerTemplate>
13                     <%# Container.PageSize %> 条/页,共 <%# Math.Ceiling((double)Container.TotalRowCount / Container.PageSize)%> 页,合计共 <%# Container.TotalRowCount %> 条记录
14                 </PagerTemplate>
15             </asp:TemplatePagerField>
16         </Fields>
17     </asp:DataPager>
18 </div>

浏览页面,已经可以看到列表里显示了用户实体数据(上一篇文章的源码中的单元测试可以为你完成测试数据的准备工作),如下图所示:

 

2 简单列表

二、条件查询

图2中的列表功能非常简单,不具有互动性,接下来为它增加按条件查询筛选功能。首先,在页面中加入查询表单控件:

1 帐号:
2 <asp:TextBox ID="tbAccount" runat="server" />
3 <asp:Button ID="btnSearch" runat="server" Text="搜索" />

然后,需要在EntityDataSource控件中加入WhereParameters查询参数。WhereParameters支持多种参数,包括ControlParameter、QueryStringParameter、FormParameter、SessionParameter、CookieParameter等等,用于不同的参数值来源。这里使用ControlParameter,从搜索表单控件获取参数值,代码如下所示:

1 <asp:EntityDataSource ID="edsUsers" runat="server" ConnectionString="name=Membership" DefaultContainerName="Membership" EntitySetName="Users" Include="UserDetail" AutoGenerateWhereClause="true">
2     <WhereParameters>
3         <asp:ControlParameter Name="Account" DbType="String" ControlID="tbAccount" PropertyName="Text" ConvertEmptyStringToNull="true" />
4     </WhereParameters>
5 </asp:EntityDataSource>

注意,除了为EntityDataSource控件加入WhereParameters,还需要设置AutoGenerateWhereClause=”true”。

运行页面,发现此时列表已支持查询功能。但是细心的读者会发现有一个问题,它不支持模糊查询。这是因为EntityDataSource控件自动生成的Where语句都是精确匹配的,要支持模糊查询,需要自定义Where属性,并设置AutoGenerateWhereClause=”false”,或不设置(该属性默认值为“false”):

1 <asp:EntityDataSource ID="edsUsers" runat="server" ConnectionString="name=Membership" DefaultContainerName="Membership" EntitySetName="Users" Include="UserDetail" Where="@Account is null or it.Account like '%'+@Account+'%'">

运行页面,模糊查询功能测试通过,如下图所示:

 

3 模糊查询

三、添加实体数据

EntityDataSource控件支持实体添加功能,只需要做很少的工作。首先,在ListView控件中加入InsertItemTemplate模板内容项:

 1 <asp:ListView ID="lvUsers" runat="server" DataSourceID="edsUsers" InsertItemPosition="LastItem">
 2  3     <InsertItemTemplate>
 4         <tr>
 5             <td><asp:TextBox ID="tbAccount" runat="server" Text='<%# Bind("Account") %>' /></td>
 6             <td></td>
 7             <td></td>
 8             <td></td>
 9             <td><asp:Button ID="btnAdd" runat="server" Text="添加" CommandName="Insert" ValidationGroup="Insert" /></td>
10         </tr>
11     </InsertItemTemplate>
12 13 </asp:ListView>

这里有两个地方非常关键,一是将实体属性与控件值进行绑定,二是设置提交按钮的事件名称为“Insert”。另外,别忘了设置ListView的InsertItemPosition属性,否则添加表单将不会显示。

然后,需要设置EntityDataSource控件的EnableInsert=”true”,使其允许通过它添加实体数据。另外,可以通过EntityDataSource控件的Inserted事件重新绑定数据,以实现页面数据刷新。前台代码如下:

1 <asp:EntityDataSource ID="edsUsers" runat="server" ConnectionString="name=Membership" DefaultContainerName="Membership" EntitySetName="Users" Include="UserDetail" Where="@Account is null or it.Account like '%'+@Account+'%'" EnableInsert="true" OnInserted="edsUsers_Changed">

后台事件代码如下:

1 protected void edsUsers_Changed(object sender, EntityDataSourceChangedEventArgs e)
2 {
3     this.edsUsers.DataBind();
4 }

可以通过InsertParameters为添加操作提供参数,这种需求一般发生在以非表单的方式提供实体属性数据的情况下,比如本例中由于密码不能为空,而且也不打算在页面提供直接录入表单,就可以通过参数为其设定默认值,如下所示:

1 <InsertParameters>
2     <asp:Parameter Name="Password" DbType="String" DefaultValue="11111111" />
3 </InsertParameters>

运行页面,实体添加功能测试通过,如下图所示:

 

4 添加实体数据

四、更新实体数据

更新实体数据功能的实现与添加实体数据类似。首先,在ListView控件中加入EditItemTemplate模板项: 

 1 <EditItemTemplate>
 2     <tr>
 3         <td><asp:TextBox ID="tbAccount" runat="server" Text='<%# Bind("Account") %>' /></td>
 4         <td><%# Eval("UserDetail.Name") %></td>
 5         <td><%# Eval("UserDetail.Sex") %></td>
 6         <td><%# Eval("UserDetail.Birthday", "{0:yyyy-MM-dd}")%></td>
 7         <td>
 8             <asp:Button ID="tbnEdit" runat="server" Text="保存" CommandName="Update" ValidationGroup="Update" />
 9             <asp:Button ID="tbnCancel" runat="server" Text="取消" CommandName="Cancel" CausesValidation="false" />
10         </td>
11     </tr>
12 </EditItemTemplate>

然后,还需要在ItemTemplate模板项中加入更新按钮控件:

 1 <ItemTemplate>
 2     <tr>
 3         <td><a href='Form.aspx?ID=<%# Eval("ID") %>' target="_blank"><%# Eval("Account") %></a></td>
 4         <td><%# Eval("UserDetail.Name") %></td>
 5         <td><%# Eval("UserDetail.Sex") %></td>
 6         <td><%# Eval("UserDetail.Birthday", "{0:yyyy-MM-dd}")%></td>
 7         <td>
 8             <asp:Button ID="btnEdit" runat="server" Text="修改" CommandName="Edit" CommandArgument='<%#Eval("ID")%>'/>
 9         </td>
10     </tr>
11 </ItemTemplate>

然后设置EntityDataSource控件允许更新,以及更新完成后重新绑定数据:

1 <asp:EntityDataSource ID="edsUsers" runat="server" ConnectionString="name=Membership" DefaultContainerName="Membership" EntitySetName="Users" Include="UserDetail" Where="@Account is null or it.Account like '%'+@Account+'%'" EnableInsert="true" EnableUpdate="true" OnInserted="edsUsers_Changed" OnUpdated="edsUsers_Changed">

运行页面,测试更新实体数据功能通过,如下图所示:

 

5 更新实体数据

五、删除实体数据

EntityDataSource删除实体数据非常简单。首先在ListView控件的ItemTemplate模板项中加入删除按钮:

1 <asp:Button ID="ibtnDelete" runat="server" Text="删除" CommandName="Delete" CommandArgument='<%#Eval("ID")%>' OnClientClick="return confirm('删除的数据不可恢复,确定要执行删除操作吗?');" />

这里需要设置按钮的命令名称属性CommandName=”Delete”,并且设置命令参数属性CommandArgument=’<%#Eval(“ID”)%>’。

然后设置EntityDataSource允许删除,并且在删除后重新绑定数据:

1 <asp:EntityDataSource ID="edsUsers" runat="server" ConnectionString="name=Membership" DefaultContainerName="Membership" EntitySetName="Users" Include="UserDetail" EnableInsert="true" EnableUpdate="true" EnableDelete="true" OrderBy="it.Account" Where="@Account is null or it.Account like '%'+@Account+'%'" OnInserting="edsUsers_Inserting" OnInserted="edsUsers_Changed" OnUpdated="edsUsers_Changed" OnDeleted="edsUsers_Changed">

运行页面,测试更新实体数据功能通过,如下图所示:

 

6 删除实体数据

 

表单

除了列表外,通过表单浏览、添加和更新数据也是常见的数据展示方式。下面就结合FormView控件,讲解如何使用EntityDataSource进行表单数据绑定。

一、数据显示

首先,在表单页面中加入EntityDataSource控件:

1 <asp:EntityDataSource ID="edsUserDetail" runat="server" ConnectionString="name=Membership" DefaultContainerName="Membership" EntitySetName="UserDetails" Where="it.ID = @ID">
2     <WhereParameters>
3         <asp:QueryStringParameter Name="ID" DbType="Guid" QueryStringField="ID" ConvertEmptyStringToNull="true" />
4     </WhereParameters>
5 </asp:EntityDataSource>

然后在表单页面中加入FormView控件:

 1 <asp:FormView ID="fvUserDetail" runat="server" DataSourceID="edsUserDetail" DefaultMode="ReadOnly">
 2     <ItemTemplate>
 3         <table border="1">
 4             <tbody>
 5                 <tr>
 6                     <th>姓名</th>
 7                     <td><%# Eval("Name") %></td>
 8                 </tr>
 9                 <tr>
10                     <th>性别</th>
11                     <td><%# Eval("Sex") %></td>
12                 </tr>
13                 <tr>
14                     <th>生日</th>
15                     <td><%# Eval("Birthday", "{0:yyyy-MM-dd}")%></td>
16                 </tr>
17             </tbody>
18         </table>
19         <asp:Button ID="btnEdit" runat="server" Text="修改" CommandName="Edit" />
20     </ItemTemplate>
21     <EmptyDataTemplate>
22         没有满足条件的数据
23         <asp:Button ID="btnAdd" runat="server" Text="添加" CommandName="Add" />
24     </EmptyDataTemplate>
25 </asp:FormView>

最后,需要在之前的列表页面中,为表单页面添加链接:

1 <asp:ListView ID="lvUsers" runat="server" DataSourceID="edsUsers" InsertItemPosition="LastItem">
2 3 <ItemTemplate>
4         <tr>
5             <td><a href='Form.aspx?ID=<%# Eval("ID") %>' target="_blank"><%# Eval("Account") %></a></td>
6 7 </ItemTemplate>
8 9 </asp:ListView>

浏览列表页面,点击包含详细信息的帐号链接,就可以进入表单页面了,如下图所示:

 

7 浏览视图

二、添加实体数据

设置ListView的DataKeyNames=”ID”和OnItemCommand=”fvUserDetail_ItemCommand”:

1 <asp:FormView ID="fvUserDetail" runat="server" DataSourceID="edsUserDetail" DataKeyNames="ID" DefaultMode="ReadOnly" OnItemCommand="fvUserDetail_ItemCommand">

在EmptyDataTemplate模板项中加入添加按钮:

1 <EmptyDataTemplate>
2     没有满足条件的数据
3     <asp:Button ID="btnAdd" runat="server" Text="添加" CommandName="Add" />
4 </EmptyDataTemplate>

在页面后台的fvUserDetail_ItemCommand事件方法中,切换FormView控件到添加视图:

1 protected void fvUserDetail_ItemCommand(object sender, FormViewCommandEventArgs e)
2 {
3     if (e.CommandName == "Add")
4         this.fvUserDetail.ChangeMode(FormViewMode.Insert);
5 }

在FormView控件中加入InsertItemTemplate模板项内容:

 1 <InsertItemTemplate>
 2     <table border="1">
 3         <tbody>
 4             <tr>
 5                 <th>姓名</th>
 6                 <td><asp:TextBox ID="tbName" runat="server" Text='<%# Bind("Name") %>' /></td>
 7             </tr>
 8             <tr>
 9                 <th>性别</th>
10                 <td><asp:TextBox ID="tbSex" runat="server" Text='<%# Bind("Sex") %>' /></td>
11             </tr>
12             <tr>
13                 <th>生日</th>
14                 <td><asp:TextBox ID="tbBirthday" runat="server" Text='<%# Bind("Birthday") %>' /></td>
15             </tr>
16         </tbody>
17     </table>
18     <asp:Button ID="btnConfirm" runat="server" Text="确定" CommandName="Insert" />
19     <asp:Button ID="btnCancel" runat="server" Text="取消" CommandName="Cancel" />
20 </InsertItemTemplate>

设置EntityDataSource控件允许插入实体数据,并在插入后重新绑定,以及设置插入参数:

1 <asp:EntityDataSource ID="edsUserDetail" runat="server" ConnectionString="name=Membership" DefaultContainerName="Membership" EntitySetName="UserDetails" Where="it.ID = @ID" EnableInsert="true" OnInserted="edsUserDetail_Changed">
2     <WhereParameters>
3         <asp:QueryStringParameter Name="ID" DbType="Guid" QueryStringField="ID" ConvertEmptyStringToNull="true" />
4     </WhereParameters>
5     <InsertParameters>
6         <asp:QueryStringParameter Name="ID" DbType="Guid" QueryStringField="ID" ConvertEmptyStringToNull="true" />
7     </InsertParameters>
8 </asp:EntityDataSource>

最后,在页面后台的edsUserDetail_Changed事件中重新绑定数据:

1 protected void edsUserDetail_Changed(object sender, EntityDataSourceChangedEventArgs e)
2 {
3     this.edsUserDetail.DataBind();
4 }

运行列表页面,点击没有详细信息的帐号链接,就能进入表单页面的空数据视图了,如下图所示:

 

8 空数据视图

点击“添加”按钮,可以将页面切换到添加视图,如下图所示:

 

9 添加视图

三、更新实体数据

首先,在FormView控件的ItemTemplate模板项中添加修改按钮:

1 <ItemTemplate>
2 3     <asp:Button ID="btnEdit" runat="server" Text="修改" CommandName="Edit" />
4 </ItemTemplate>

为FormView控件加入EditItemTemplate模板项:

 1 <EditItemTemplate>
 2     <table border="1">
 3         <tbody>
 4             <tr>
 5                 <th>姓名</th>
 6                 <td><asp:TextBox ID="tbName" runat="server" Text='<%# Bind("Name") %>' /></td>
 7             </tr>
 8             <tr>
 9                 <th>性别</th>
10                 <td><asp:TextBox ID="tbSex" runat="server" Text='<%# Bind("Sex") %>' /></td>
11             </tr>
12             <tr>
13                 <th>生日</th>
14                 <td><asp:TextBox ID="tbBirthday" runat="server" Text='<%# Bind("Birthday") %>' /></td>
15             </tr>
16         </tbody>
17     </table>
18     <asp:Button ID="btnConfirm" runat="server" Text="确定" CommandName="Update" />
19     <asp:Button ID="btnCancel" runat="server" Text="取消" CommandName="Cancel" />
20 </EditItemTemplate>

然后设置EntityDataSource控件允许更新,并在更新操作后重新绑定数据:

1 <asp:EntityDataSource ID="edsUserDetail" runat="server" ConnectionString="name=Membership" DefaultContainerName="Membership" EntitySetName="UserDetails" EnableInsert="true" EnableUpdate="true" Where="it.ID = @ID" OnInserted="edsUserDetail_Changed" OnUpdated="edsUserDetail_Changed">

浏览列表页面,点击包含详细信息的帐号链接,进入表单页面的数据浏览视图,如下图所示:

 

10 带修改按钮的浏览视图

点击“修改”按钮,就可以进入用户详细信息更新视图了,如下图所示:

 

11 更新视图

 

总结

本文在简单分析了ASP.NET数据源控件的技术架构后,通过实例依次实现了EntityDataSource结合ListView控件进行数据增删改查,以及结合FormView控件进行数据浏览、添加和更新的功能,这些功能基本上覆盖了50%的页面数据应用场景。

EntityDataSource控件非常强大,但要用好它却不容易,需要不断的实践方能体会它的奇妙之处。另外,你可以在参数控件、事件方法等方面扩展它,使其更强大,更贴近你的项目需求。

下一篇文章将带领到家领略LINQ to Entities查询技术与Entity Framework技术双剑合璧的强大威力。

 

附件下载:示例源码+本文PDF版本

posted @ 2013-03-11 23:18 Apollo.NET 阅读(...) 评论(...) 编辑 收藏