前言
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技術雙劍合璧的強大威力