ASP.NET 2.0 数据操作:插入、更新、删除数据时的事件

来源:百度文库 编辑:神马文学网 时间:2024/04/29 07:36:50
使用GridView,DetailsView 或者FromView空间,编辑、插入、删除数据时。当用户完成这些处理过程中程序需要执行一系列操作,在GridView里编辑一行数据时,Edit button 被UpDate 和 Cancel button替换,BoundFields呈现为Textbox,用户点击update button时,执行以下操作
1. GridView把DataKeyName字段的值和用户输入的数据传给ObjectDataSource的UpdateParameters。
2. GridView调用ObjectDataSource的Update()方法,Update接着调用底层数据访问对象的相应的方法。
3. 底层数据访问对象更新数据库,然后GridView重新绑定
在这一系列步骤里,会有不同的事件被引发,我们可以通过建立事件处理函数来添加自定义的逻辑处理。例如,在步骤一,GridView的RowUpdating事件被触发,如果输入的数据没有通过验证,可以再次作废这次提交。调用Update()方法时ObjectDatasource的Updating事件被触发。我们可以在事件处理函数可以修改UpdateParameters参数使之符合程序的要求,底层对象完成更新后,ObjectDataSource的,Updated事件被触发,这里可以了解update操作后详细的结果,比如多少影响了多少数据行?有没有异常产生。步骤2后GridView的RowUpdated事件被触发。事件处理函数可以检测更多的更新操作信息。
Figure 1 描绘了GridView更新操作的sequence图,这种事件模式不是GridView更新数据所特有的,GridView, DetailsView, 或者FormView 和ObjectDataSource,插入数据,删除数据,执行同样的序列。
本指南要解释如何在Asp.net数据控件使用这些事件来增强数据操作的功能。我们将要看到如何用户化编辑界面和如何更新部分的product字段。
Step 1: Updating a Product’s ProductName and UnitPrice Fields
在上一个指南中边界数据必须包括product所有非只读字段。如果我们从GridView移除掉一个字段,例如QuantityPerUnit,结果我们更新时,数据控件将不能给ObjectDataSource 的 QuantityPerUnit 这个UpdateParameters赋值,ObjectDataSource传给UpdateProduct业务逻辑层方法一个空值,将把数据库这行数据里的QuantityPerUnit列变为NULL。如果去除的是必添字段比如ProductName,结果引发异常“Column ‘ProductName‘ does not allow nulls”,所以ObjectDataSourc的UpdateParameters集合与相应的方法参数匹配。
如果我们做的数据web控件允许用户仅仅更新这些字段的子集。我们需要编程在ObjectDataSource的Updating事件里设置丢失的ObjectDataSource 的UpdateParameter的值,或者建立一个仅包含这些字段的业务逻辑层的方法,下面具体解释如果操作
现在,建立一个编辑模式仅包含ProductName and UnitPrice字段的GridView,这个GridView编辑界面只能让用户修改这两个字段。因为编辑界面只提供这product的部分字段值,且ObjectDataSource调用了现有的业务逻辑层的UpDateProduct方法,我们需要在UpDating事件处理函数里处理那些缺失的参数,或者建立一个新的仅包括这些参数的业务逻辑层UpDateProduct方法。本指南使用后一种方法。下面我们重载UpdateProduct方法,他只包括3个参数productName, unitPrice, and productID,代码如下
[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Update, false)]
public bool UpdateProduct(string productName, decimal? unitPrice, int productID)
{
Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID);
if (products.Count == 0)
// no matching record found, return false
return false;
Northwind.ProductsRow product = products[0];
product.ProductName = productName;
if (unitPrice == null) product.SetUnitPriceNull(); else product.UnitPrice = unitPrice.Value;
// Update the product record
int rowsAffected = Adapter.Update(product);
// Return true if precisely one row was updated, otherwise false
return rowsAffected == 1;
}
同原来的UpdateProduct一样,先通过输入的ProductId检测表中是否有要更新的数据,如果没有,返回false,表明更新失败。否则通过TableAdpater的Update()方法更新已存在的数据的ProductName和UnitPrice字段。
因为ProductsBLL改变了,我们建立一个简单的GridView,打开EditInsertDelete文件夹下的DataModificationEvents.aspx,添加一个GridView,和ObjectDataSource,配置ObejctDataSource的Select影射到ProductsBLL的GetProducts,Update影射到UpdateProduct重载的方法如Figure2所示,
我们的例子只是说明如果编辑数据,不包括插入和删除数据,所以ObjectDataSource的Insert方法和Delete方法不影射到任何ProductsBLL的任何方法,在向导里在Insert和DELETE标签里选择(None)。
完成向导后,通过GridView的智能标记把Enable Editing打勾。
完成了建立数据源的向导,并把它绑定到GridView,Visual Studio会为它们自动建立代码,在Source view可以看到ObjectDataSource的代码如下。
TypeName="ProductsBLL" UpdateMethod="UpdateProduct">






因为没有影射ObjectDataSource的Insert()和Delete()方法,所以这里没有InsertParameter和DeleteParameters节。Update()方法影射到重载的UpdateProduct方法,所以UpdateParameters节仅有3个Parameter实例。
注意ObjectDatasource的OldValuesParameterFormatString属性被声明为original{0},这是配置数据源时Visual Studio自动生成的。然而,我们业务逻辑方法不需要原来的ProductId之所以把它从ObjectDataSource的代码去掉。
注意:如果你简单的在设计视图里的属性窗口去掉OldValuesParamerFormatString属性值,在代码里这个属性依旧存在,只是被设为空字符串,应该直接在代码里删除它,或者在属性窗口把它设想为默认值{0}。
现在ObjectDataSource只有带着product’s name, price, 和ID 的UpdateParameters,
Visual Studio 也把product的字段添加成GridView的BoundField or CheckBoxField。
用户点Update button ,GridVeiw枚举所有的非只读字段,把它们的用户输入赋给ObjectDataSource的UpdateParameters集合相应的参数,如果没有相应的参数,GridView会自己添加一个,因此如果GridView包含product所有字段的BoundFields and CheckBoxFields,ObjectDataSource要使用所有的参数来调用重载的UpdateProduct,尽管只需要3个参数。同样的GridView中绑定的所用product非只读字段不符合重载的UpdateProduct方法要求的输入参数,所以更新时会引发异常
为了确保ObjectDataSource调用UpdateProduct方法时获得正确的参数,我们需要限制GridView的可编辑字段只包括Productname 和UnitPrice。我们可以删除其余字段,或者把其余字段设为只读。本指南让我们简单的移除除了ProductName和UnitPrice外的BoundFields,GridView代码声明如下。
DataSourceID="ObjectDataSource1" EnableViewState="False">






即使重载的UpdateProdcut要求两个输入参数,我们只提供了连个,这是因为ProductId输入参数是作为主键传送的,因为ProductId是GridView的DatakeyName属性。
我们的GridView,通过UpdateProduct的重载函数,允许用户只编辑name和price。
Improving the UnitPrice Formatting
这个GridView的例子,UnitPrice字段是么有格式要求的。Price字段单位是金额这样的显示效果是不好的。应该显示为金额符号加上4位小数。在非编辑状态下修改格式,简单的把UnitPrice BoundFields的DataFormatString属性设为{0:c}且HtmlEncode属性设为false。
随着这次的修改,非编辑状态下的price显示为金额格式。编辑模式依旧没有显示为金额格式。
DataFormatString属性可以应用于编辑界面。把Boundfield的ApplyformatInEditMode属性设为true。
现在UnitPrice在编辑状态下也显示为金额格式。
然而,现在更新product,比如用户输入“$19.00”,会引发一个FormatException异常。因为GridView试图把用户输入传入ObjectDatasource的UpdateParameters集合。输入的其实是一个字符串”$19.00”,程序需要把它转换为所需的decimal。为了补救这些,我们需要建立一个GridView的RowUpdating事件处理程序,在那里把用户输入转为正确的数据。
GridView’s RowUpdating事件接受两个参数,一个对象是GridViewUpDateEventArgs类型。它有一个NewValues字典类型的属性。在这里就是用户提供给ObjectDataSource的UpdateParameters集合的值。我们可以重写已经存在的UnitPrice值。代码如下。
protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
if (e.NewValues["UnitPrice"] != null)
e.NewValues["UnitPrice"] = decimal.Parse(e.NewValues["UnitPrice"].ToString(), System.Globalization.NumberStyles.Currency);
}
如果用户输入的UnitPrice值(比如“$19.00”),这个之会被Decimal.Parase重写为decimal值。.
Step 2: Prohibiting NULL UnitPrices
数据库里允许Produc表的UnitPrice列允许输入控制。但是程序可能不允许这样,因此,如果用户输入一个空值,需要显示一个错信息来提示他。
GridViewUpdateEventArgs对象被传入GridView的Rowupdateing事件处理函数。它有一个Cancel属性。如果设为true,就结束更新。现在让我们修改RowUpdating事件处理函数。如果用户输入控制,就把这个对象Cancel设为true,并显示一个错误消息。
添加一个Label 控件,命名为MustProvideUnitPriceMessage。如果用户有错误的输入,则显示出来“You must provide a price for the product”,再在Style.cs建立一个新的CSS类定义如下
.Warning
{
color: Red;
font-style: italic;
font-weight: bold;
font-size: x-large;
}
最后设定这个Label的CssClass属性为Warning。具体显示如下图。
默认的这个label应该是隐藏的。于是在Page_Load事件处理函数设定它的Visible属性为false
protected void Page_Load(object sender, EventArgs e)
{
MustProvideUnitPriceMessage.Visible = false;
}
如果用户更新Product但没有输入UnitPice,需要中断这个处理。并显示错误信息。代码如下。
protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
if (e.NewValues["UnitPrice"] != null)
e.NewValues["UnitPrice"] = decimal.Parse(e.NewValues["UnitPrice"].ToString(), System.Globalization.NumberStyles.Currency);
else
{
// Show the Label
MustProvideUnitPriceMessage.Visible = true;
// Cancel the update
e.Cancel = true;
}
}
Figure 13: A User Cannot Leave UnitPrice Blank
目前为止,解释了如何在GridView的RowUpdating事件处理函数编程改变ObjectDataSource的UpdateParameters参数。还有如何作废更新的处理过程。这些概念也适用于DetailView和FormView。也适用于它们的Insert和delete处理过程。
这些就是ObjectDataSource级别的事件处理函数主要任务。这些事件在底层对象处理数据之前被触发。它提供最后的机会去修改输入参数和中断处理流程。这些事件处理函数都有一个ObjectDataSourceMethodEventArgs类型的输入参数,这个参数有两个属性十分重要。
• Cancel,如果设为true,则中止操作。
• InputParameters,它包括了所有的输入参数集合,
UpdateParameters 还有DeleteParameters,这些类型的对象依赖于何种事件被触发(Instering,Updaing,或者Deleting),会被传入相应的事件处理函数。
以上解释了在ObjectDataSource级别上参数如何处理。下面在页面上加一个DetailsView控件,可以让用户把新的product添加到数据库。为了和以上说明一致,这里只允许用户输入新的Productname,和UnitPrice字段。默认下DetailsView 插入界面没有提供的字段会被把空值插入数据库,我们需要在ObjectDataSource的Inserting事件处理函数防止这些默认参数值。下面看看如何做。
Step 3: Providing an Interface to Add New Products
从工具栏上拖一个DetailsView到GridView上面,清除Height和Width属性,绑定到页面已有的ObjectDataSource,这会把Product的字段添加为BoundField或者CheckBoxField。为了能过让Details添加数据,需要在智能标记上选择Enable Inserting选项。然而,因为前面ObjectDataSource的insert()方法没有影射到任何ProductsBLL类的方法。
现在选择ObjectDataSource职能标记配置数据源,进入向导,先把ProductsBLL绑定到ObjectDataSource,接着影射ObjectDataSource的Insert()方法到ProductsBLL的AddProduct,因为DataObjectMethodAttribute属性,所以这些方法仍然是默认的方法。
配置万Insert,接着依然把DELETE标签的下拉列表选为(None).
通过这些改变,ObjectDataSource代码会包括InsertParameter集合,如下所示
TypeName="ProductsBLL" UpdateMethod="UpdateProduct" OnUpdating="ObjectDataSource1_Updating" InsertMethod="AddProduct" OldValuesParameterFormatString="original_{0}">

















再次运行向导,会添加OldValuesParameterFormatString属性,花一些时间去除它,或把它设为默认值{0}。
因为ObjectDataSource提供了插入数据的能力,DetailsView的智能标记现在可以让你选择Enable Inserting checkbox,选择它,现在DetailsView仅有两个BoundFields(ProductName、UnitPrice)和一个CommandField,代码如下
DataSourceID="ObjectDataSource1" EnableViewState="False">






Figure16显示了游览本页的效果。正如你看到的DetailsView列出了第一个product的名字(Chai),然而我们需要一个插入界面,可以让用户快速插入数据到数据库中。
为了让DetailsView显示为插入模式,我们需要设定DefaultMode属性为Inserting,DetailsView会呈现为插入模式,如Figure17显示的那样。
当用输入了Product的name和price(比如“Acme Water” 和1.99 ),点击Insert button,页面回送服务器一个插入数据的流程开始了,最后一个新的产品插入的数据库。DetailsView负责插入,GridView在插入后自动绑定到新的数据。如Figure18显示的那样
这里GridView并没有显示所有的product字段(CategoryID,SupplierID,QuantityPerUnit 等等),你可以通过以下步骤看到这些值
1. 进入Visual Studio的Server Explorer。
2. 展开NORTHWND.MDF节点
3. 右击Product数据库的表节点
4. 选择显示表数据
如Figure19显示的那样,这会列出Product表所有记录。我们新输入的记录ProductID, ProductName, and UnitPrice被赋予NULL值
某些情况下我们需要提供默认值代替NULL,例如:可能数据库会不允许空值等等。我们可以编程设定DetailsView的InputParameters集合的值,这些操作可以在DetailsView的ItemInerting事件,或者ObjectDataSource的Inserting事件处理函数里做。前面我们已经看到用Data Web Control 提交之前的事件处理这一切,现在我们在ObjectDataSource的事件里处理它
Step 4: Assigning Values to the CategoryID and SupplierID Parameters
在这个指南中假设我们的程序添加新的product时。它的CategroyID和SupplierID默认值为1
从前面的指南我们知道ObjectDataSource提交数据时有一对事件要被触发。当Insert()被调用,ObjectDataSource首先触发Inserting事件,接着调用Insert()方法影射的方法,最后触发Inserted事件。Inserting事件处理函数为我们提供了最后的机会来修改输入参数或者中断处理。
注意:实际应用程序应该让用户可以详细指定category and supplier的值而不是简简单单的设为1,这里只是解释如何编程设定输入值。
添加ObjectDataSource的Inserting事件,注意事件处理函数有两个参数,第二个是ObjectDataSourceMethodEventArgs类型的对象。可以通过它访问输入参数集合。或者中断处理过程。
protected void ObjectDataSource1_Inserting(object sender, ObjectDataSourceMethodEventArgs e)
{
}
InputParameters属性包括了ObjectDataSource的InsertParameters集合,简单使用e.InputParameters["paramName"] = value ,就可以把e CategoryID and SupplierID值设为1,代码如下。
protected void ObjectDataSource1_Inserting(object sender, ObjectDataSourceMethodEventArgs e)
{
e.InputParameters["CategoryID"] = 1;
e.InputParameters["SupplierID"] = 1;
}
先在我们添加一个新的Product,如Figure20看到的新的记录的CategoryID and SupplierID值为1