Web窗体模型绑定第一部分:数据选择(ASP.NET vNext系列)
[原文发表地址] Web Forms Model Binding Part 1: Selecting Data (ASP.NET vNext Series)
[原文发表时间] 2011-09-05 21:58
这是我写的ASP.NET vNext系列博文的第三篇。
下一版的.NET和Visual Studio包括了许多很棒的新功能。有了ASP.NET vNext,你会看到许多令人激动的Web窗体和MVC改进——还有它们建立的基础ASP.NET核心库的改进。
这两个礼拜我会写3篇博文来讲讲Web窗体对新模型绑定的支持,这是第一篇。模型绑定是ASP.NET Web窗体现有数据绑定系统的扩展,提供了代码为主的数据访问范例。它利用了我们最早介绍的ASP.NET MVC模型绑定概念,并通过Web窗体服务器控制模型很好地将它们融合了起来。
如今的数据绑定背景介绍
Web窗体囊括了一系列数据源控件(比如SqlDataSource,EntityDataSource, LinqDataSource),能让你直接从服务器端控件连接数据源。许多开发者都喜欢对他们的数据访问逻辑拥有完全控制——并用代码编写这个逻辑。
在之前版本的Web窗体中,这可以通过直接设置控件的DataSource属性,然后在页面的后台代码中调用DataBind()函数来完成。虽然这个方法对很多场景都适用,但是对于有大量数据的控件(比如GridView)来说,这种方法不能很好的支持像排序,分页和编辑之类的自动操作。
还有一个可行的方法是使用ObjectDataSource控件。这个控件可以将UI代码和数据访问层更清晰地分离出来,让数据控件提供自动功能,比如分页和排序。不过,它虽然在选择数据这部分很好用,但它执行双向数据绑定还是很繁琐,只支持简单的属性(没有高级的复杂类型绑定),而且还会常要求开发者写许多复杂代码来处理许多场景(包括像验证错误这种常见的场景)。
模型绑定介绍
ASP.NET vNext在Web窗体中为“模型绑定”提供了许多新的支持。
模型绑定旨在简化代码为主的数据访问逻辑,但同时保持丰富的双向数据绑定框架的优势。它承袭了我们最早介绍的ASP.NET MVC模型绑定样式,并融入了Web窗体服务器控件模型。这样用Web窗体来执行常见的CRUD风格场景就变得简单了,同时还能让你使用任何数据访问技术(EF, Linq, NHibernate, DataSets, 原始 ADO.NET等等)
我这周还会写些其他博文,介绍如何利用新模型绑定功能。今天的博文中我会展示如何使用模型绑定来检索数据——并在GridView控件中实现排序和分页。
用SelectMethod检索数据
模型绑定是一个专注于代码的数据绑定方法。
它能让你在页面的后台代码文件中编写CRUD辅助函数,并很方便与页面中的任意服务器控件相连。然后服务器控件就会在适当的时候,在页面生命周期内调用上述函数,并进行数据绑定。
来看一个简单的例子,我们使用<asp:gridview>控件。下面的GridView有4个栏——其中3个是标准的BoundField,第4个是TemplateField。注意我们是如何在GridView上设置ModelType属性到Category对象上的——这个能让我们在templatefield中实现强类型数据绑定(比如Item.Products.Count而不是使用Eval() 函数):
<asp:GridView ID="categoriesGrid" runat="server" ModelType="WebApplication1.Model.Category"
SelectMethod="GetCategories" AutoGenerateColumns="false">
<Columns>
<asp:BoundField DataField="CategoryID" HeaderText="ID" />
<asp:BoundField DataField="CategoryName" HeaderText="Name" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField HeaderText="# of Products">
<ItemTemplate><%# Item.Products.Count %></ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
我们对GridView进行了配置,在页面的后台代码文件中将GridView的SelectMethod属性设置为指向GetCategories()函数,从而实现使用模型绑定来检索数据。这个GetCategories()函数如下所示:
public IQueryable<Category> GetCategories() {
var northwind = new Northwind();
return northwind.Categories.Include(c => c.Products);
}
上面的例子中,我用EF Code First来执行LINQ查询,从Northwind示例数据库中返回category清单。注意我们无需在后台代码中执行数据库查询——我可以通过一个仓储或数据访问层来执行,或者使用GetCategories()方法来连接控件。
当我们运行页面,GridView就会自动调用上述函数,然后检索数据,并在页面上做如下显示:
避免N+1选择
看了上面的代码,你可能会注意到我们在LINQ查询中使用的是.Include(c=>c.Products)辅助扩展。这就能告诉EF要修改查询,这样除了检索Category信息之外,还包括了相关联的Products(避免为返回的每行信息,而分开调用数据库)。
排序和分页支持
我们可以在GetCategories() 函数中使用IEnumerable<Category> ——或者实现像List<Category>这样的接口类型来返回categories。尽管我们用的是IQueryable<Category>接口来返回category:
public IQueryable<Category> GetCategories() {
var northwind = new Northwind();
return northwind.Categories.Include(c => c.Products);
}
返回的IQueryable<T>的好处就是它能在延迟执行查询,还能在执行前允许数据绑定控件对查询进行修改。这对那些支持分页和排序的控件来说是很有用的。这些控件可以在执行前自动在IQueryable<T>查询上添加排序和分页操作。这样使得在代码上实现排序和分页变得简单了——并且确保了排序和分页在数据库上完成,和超级高效。
要用GridView实现排序和分页,我们要修改它的AllowSorting和AllowPaging属性变为True,然后将默认PageSize设为5。同时我们还在两个栏中,指定合适的SortExpression 。
<asp:GridView ID="categoriesGrid" runat="server" AutoGenerateColumns="false"
AllowSorting="true" AllowPaging="true" PageSize="5"
ModelType="WebApplication1.Model.Category"
SelectMethod="GetCategories">
<Columns>
<asp:BoundField DataField="CategoryID" HeaderText="ID" SortExpression="CategoryID" />
<asp:BoundField DataField="CategoryName" HeaderText="Name" SortExpression="CategoryName" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField HeaderText="# of Products">
<ItemTemplate><%# Item.Products.Count %></ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
现在我们运行页面,我们就能分页和排序数据了:
将只从数据库中检索出category并显示在当前排序页——因为EF会优化查询,将排序和页面操作看做数据库查询的一部分来执行,不会在中间层进行排序/分页。所以即使有大量的数据,排序/分页也会很高效。
模型绑定和SelectMethod的简短视频
Damiana Edwards做了一个很棒的90秒视频,展示了使用模型绑定来实现具有排序和分页功能的GridView场景。你可以点击这里观看90秒视频。
总结
ASP.NET vNext支持新的模型绑定是现有Web窗体数据绑定系统的完美演变。它承袭了ASP.NET MVC(你会在之后的很多文章中看到它)模型绑定系统的理念和功能,使得代码为主的数据访问范例更简单灵活。
在之后的此系列博文中我会扩展模型绑定,看看我们怎么能简单地将筛选场景融入我们的数据选择场景,还有如何处理编辑场景(包括那些使用验证的)。
希望这些对你有帮助。
Scott