次の方法で共有


WebForm模型绑定第三部分:更新和验证(ASP.NET 4.5系列)

[原文发表地址]  Web Forms Model Binding Part 3: Updating and Validation (ASP.NET 4.5 Series)

[原文发表时间] 2011-10-30 22:58

这是我在ASP.NET 4.5上写的第五篇系列博文

下一版的.NET和Visual Studio包含了一大堆全新的功能和特点。有了ASP.NET4.5你会发现许多很不错的有关WebForm和MVC的改进,还有核心ASP.NET库的改进。

今天这篇是三篇讨论WebForm中全新模型绑定支持的博文中的第三篇。模型绑定是ASP.NETWebForm中现有数据绑定系统的扩展,提供代码为主的数据访问范例。它吸取了之前介绍过的ASP.NET MVC模型绑定概念——并很好地与WebForm服务器控制模型相融合。

如果你还没有读过这个系列的前两部分,谈论了通过像GridView这样的数据控件中的选择函数属性来选择数据,还有根据用户输入筛选数据

在今天的博文中,我们会看看模型绑定如何在更新数据时改进数据绑定体验的。

开始

让我们从先前博文中的GridView示例开始,经配置使用模型绑定来显示Northwind产品表中的数据。GridView调用已配置的GetProducts方法,使用代码先行的Entity Framework 来返回Products属性,这个属性呢存在于Northwind数据上下文实例中。

DataKeyNames属性设置为模型类型中的主要键,这是很重要的,所以GridView可以和页面一起在浏览器和服务器间往返这个值。

<asp:GridView ID="productsGrid" runat="server" DataKeyNames="ProductID"

    ModelType="ModelBindingPart3.Product"

    AllowPaging="true" AllowSorting="true" AutoGenerateColumns="false"

    SelectMethod="GetProducts">

    <Columns>

        <asp:BoundField DataField="ProductID" HeaderText="ID" />

        <asp:BoundField DataField="ProductName" HeaderText="Name" SortExpression="ProductName" />

        <asp:BoundField DataField="UnitPrice" HeaderText="Unit Price" SortExpression="UnitPrice" />

        <asp:BoundField DataField="UnitsInStock" HeaderText="# in Stock" SortExpression="UnitsInStock" />

    </Columns>

</asp:GridView>

以下是我们的后台代码文件的内容(包含 GetProducts() 方法) :

public partial class _Default : Page

{

    private Northwind _db = new Northwind();

    public IQueryable<Product> GetProducts()

    {

        return _db.Products;

    }

}

运行这个页面域,期望的表格结果包含产品数据:

image

因为我们的GetProducts()方法会返回IQueryable<Product>,用户可以简单地在GridView中通过数据分页分类。只有可以在任何页面上可见的十行才被返回到数据库。

支持编辑

我们可以通过把AutoGenerateEditButton属性设置为“true”来支持GridView行内编辑。现在GridView可以为每一行显示编辑链接,用户可以点击来转换行编辑模式。

下一步,我们要配置GridView来调用更新方法(我们会在代码后置文件中做些修改)。我们可以通过设置UpdateMethod属性至函数名实现这个。在这个例子中,就是“UpdateProduct”。我们的GridView标记就会如下所示:

<asp:GridView ID="productsGrid" runat="server" DataKeyNames="ProductID"

    ModelType="ModelBindingPart3.Product"

    AllowPaging="true" AllowSorting="true"

    AutoGenerateColumns="false" AutoGenerateEditButton="true"

    SelectMethod="GetProducts" UpdateMethod="UpdateProduct">

    <Columns>

        <asp:BoundField DataField="ProductID" HeaderText="ID" />

        <asp:BoundField DataField="ProductName" HeaderText="Name" SortExpression="ProductName" />

        <asp:BoundField DataField="UnitPrice" HeaderText="Unit Price" SortExpression="UnitPrice" />

        <asp:BoundField DataField="UnitsInStock" HeaderText="# in Stock" SortExpression="UnitsInStock" />

    </Columns>

</asp:GridView>

我们现在运行页面,可以点击记录边的一个“编辑”链接,转换到编辑模式:

image

我们现在可以在我们代码后置文件中实行UpdateProduct()函数。有很多方法可以让我们做到这个。

方法1

我们的第一种方法会让WebForm模型绑定系统传递一个产品实例到更新函数,我们可以把它附加到EF代码先行上下文中,在数据库中更新它的内容:

public void UpdateProduct(Product product)

{

    // 'product' was implicitly model bound using data-control values

    _db.Entry(product).State = System.Data.EntityState.Modified;

    _db.SaveChanges();

}

我们上述方法选取了GridView绑定到的类型的单一参数——也就是“产品”类型。当UpdateProduct方法被模型绑定系统调用,它就会隐性地创建一个产品实例,试图把数据控件中的值绑定到它的成员上。我们的UpdateProduct函数然后就会告诉EF代码先行,产品对象的状态已经修改,就会在最终保存更改前标记这个对象是已修改的。

方法2

虽然这个方法对简单的例子都使用,你的数据控件不会给你数据对象上的每一个成员提供值,因为他们不会被显示在页面上,或者他们代表与其他对象的关系。在这种情况下,更好的办法是,先从数据库中加载需要更新的对象,然后显性的指导模型绑定系统对它能绑定的数据控件值进行绑定。我们来用这个方法更新一下函数:

public void UpdateProduct(int productId)

{

    var product = _db.Products.Find(productId);

    // Explicitly model bind data-control values onto 'product'

    TryUpdateModel(product);

    _db.SaveChanges();

}

这次,WebForm模型绑定系统会从数据控件的DataKey集合中(它会隐性操作,无需提供值的属性)适配productId参数。然后我们从数据库中检索产品,调用TryUpdateModel来模型绑定数据控件中的值到对象上。完成后,保存更改到数据库。

模型验证

当然,大部分数据模型包含一些验证规则。为了促进这个,WebForm中的模型绑定系统支持使用模型验证,用和ASP.NET 动态数据,MVC,实体框架和Silverlight RIA服务一样的System.ComponentModel.DataAnnotations命名空间。你可以用这些属性来装点你模型类别的属性,来提供更多有关模型“形状”的信息,包括详细的哪个属性需要一个值,以及验证值的范围。

我们用与数据库中纲要相符的验证信息来更新我们的产品类:

image

我们可以通过添加下列属性到我们的产品类:

public class Product

{

    public int ProductID { get; set; }

    [Required, StringLength(40)]

    public string ProductName { get; set; }

    [StringLength(20)]

    public string QuantityPerUnit { get; set; }

    [DataType(DataType.Currency)]

    public decimal? UnitPrice { get; set; }

    public short? UnitsInStock { get; set; }      

    public short? UnitsOnOrder { get; set; }

    public short? ReorderLevel { get; set; }      

    public bool Discontinued { get; set; }

    public int? CategoryID { get; set; }

    public virtual Category Category { get; set; }

}

现在,值被模型绑定到这个类型, Web Form模型绑定系统会追踪在页面的模型状态属性中有没有与这些验证规则相违背的内容。我们就能在保存更改前显性检查属性来确保模型状态是有效的:

public void UpdateProduct(int productId)

{

    var product = _db.Products.Find(productId);

    TryUpdateModel(product);

    // Check whether there were any validation errors

    if (ModelState.IsValid)

    {

        _db.SaveChanges();

    }          

}

要让这些模型状态错误在无效时显示在页面上,我们可以添加一个<asp:ValidationSummary>控件,把它的ShowModelStateErrors属性设置为“true”:

<asp:ValidationSummary runat="server" ShowModelStateErrors="true" />

现在,如果我们用无效值来更新记录,GridView就会保持编辑模式,模型状态错误消息就会由验证小结显示:

image

你还可以添加自定义错误消息到页面模型状态,来表示没有涵盖在验证属性中的其他错误状况。就像ASP.NET MVCControllers,WebForm页面基类有一个“模型状态”属性,你可以使用它来显示页面中验证控件可访问的自定义错误消息,显示任何你想要的错误消息。

模型绑定和筛选的快速教学视频

Damiana Edwards做了一个很棒的90秒视频,展示了如何使用模型绑定来实行模型绑定更新场景。你可以点击这里观看90秒视频。

总结

ASP.NET WebForm4.5中的模型绑定系统让用户更简单地处理数据,使用代码为主的数据访问纲要进行输入。它借鉴了我们之前介绍的ASP.NET MVC的一些模型绑定概念,支持持续在MVC和WebForm使用DataAnnotation属性对模型对象来应用验证。所有在这里展示的技术都能被应用到其他ASP.NET WebForm中的数据控件,包括FormView, DetailsView和ListView。

希望对你们有帮助。

Scott

说明:除了博客之外,我使用Twitter来快速发表博文以及分享链接。 我的Twitter是 @scottgu