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