您现在的位置是:网站首页> 编程资料编程资料

在ASP.NET 2.0中操作数据之五十五:编辑和删除现有的二进制数据_自学过程_

2023-05-24 268人已围观

简介 在ASP.NET 2.0中操作数据之五十五:编辑和删除现有的二进制数据_自学过程_

导言:

  在前面的3章里我们为处理二进制数据添加了很多的功能。我们首先在表Categories里添加BrochurePath列,并更新了体系结构。同样,为了处理表Categorie里现有的Picture列,我们在数据访问层和业务逻辑层里增加了相应的方法。同时我们创建一个页面,在GridView控件里显示二进制数据——包含一个指向说明小册子的下载链接,并将每个类的图片显示在元素里。同时我们添加一个DetailsView控件,供用户添加新的类,并上传其图片和小册子数据。

  剩下的就是添加编辑和删除功能,本章我们将通过GridView控件内建的编辑和删除功能来实现。当编辑一个类时,我们允许用户用任意指定的图片将原来的换掉;也可以用新的小册子将现有的替换掉,甚至不再包含小册子文件。让我们开始吧!

第1步:更新数据访问层

  虽然数据访问层包含自动生成的Insert, Update和Delete方法,但它们都基于CategoriesTableAdapter的主查询,因此并不包含Picture列。自然,Insert和Update方法也不包含picture列的相应参数。就像56章做的那样,我们需要为更新Categories表而创建新的TableAdapter方法。

  右键点击CategoriesTableAdapter的顶部,选择“添加查询”,打开TableAdapter查询设置向导,我们首先选择“使用SQL语句”,点Next,再选“UPDATE”,再点Next.

//img.jbzj.com/file_images/article/201605/2016051710105725.gif
图1:选择“UPDATE”选项

我们现在需要指定UPDATE SQL语句。向导自动创建一个基于TableAdapter主查询的UPDATE语句(它更新CategoryName, Description和BrochurePath值)。更新该语句以包含Picture列,以及@Picture参数,像如下这样:

 UPDATE [Categories] SET [CategoryName] = @CategoryName, [Description] = @Description, [BrochurePath] = @BrochurePath , [Picture] = @Picture WHERE (([CategoryID] = @Original_CategoryID))

最后,向导要求我们为新的TableAdapter方法命名,我们取为UpdateWithPicture,再点Finish。

//img.jbzj.com/file_images/article/201605/2016051710105726.gif
图2:为新方法命名为UpdateWithPicture

第2步:添加新的业务逻辑方法

除了更新DAL外,我们需要更新BLL以包含更新、删除类的方法。以下是表现层需要调用的方法:

为了删除一个类,我们使用CategoriesTableAdapter的自动生成的Delete方法,在类CategoriesBLL里添加如下的方法:

 [System.ComponentModel.DataObjectMethodAttribute (System.ComponentModel.DataObjectMethodType.Delete, true)] public bool DeleteCategory(int categoryID) { int rowsAffected = Adapter.Delete(categoryID); // Return true if precisely one row was deleted, otherwise false return rowsAffected == 1; }

  本教程,为了更新一个类,我们将创建2个方法。一个方法接受picture值,并调用我们刚刚添加到CategoriesTableAdapter里的UpdateWithPicture方法。另一个方法只接受CategoryName, Description和BrochurePath值, 并调用CategoriesTableAdapter类里自动生成的Update语句。为什么要使用2种方法呢?某些情况下,用户更新类时同时更新其图片,这时就需要上传一张新图片。上传图片的数据将在UPDATE语句里用到;另一种情况,用户只想更新类的name和description信息,因此我们需要使用2种更新方法。业务逻辑层会根据是否传入picture值来判断使用哪种方法。

  为达该目的,我们要在CategoriesBLL类里添加2个方法,名字都是UpdateCategory,第一个方法接受的参数包括3个string,1个byte数组和1个int;第二个方法接受的参数包括3个string和1个int。3个字符串参数代表类的name, description和brochure文件路径,byte数组包含的是类的picture数据,int代表类记录的CategoryID,我们注意到,当传入的byte数组为null时,第一个方法将调用第二个方法。

 [System.ComponentModel.DataObjectMethodAttribute (System.ComponentModel.DataObjectMethodType.Update, false)] public bool UpdateCategory(string categoryName, string description, string brochurePath, byte[] picture, int categoryID) { // If no picture is specified, use other overload if (picture == null) return UpdateCategory(categoryName, description, brochurePath, categoryID); // Update picture, as well int rowsAffected = Adapter.UpdateWithPicture (categoryName, description, brochurePath, picture, categoryID); // Return true if precisely one row was updated, otherwise false return rowsAffected == 1; } [System.ComponentModel.DataObjectMethodAttribute (System.ComponentModel.DataObjectMethodType.Update, true)] public bool UpdateCategory(string categoryName, string description, string brochurePath, int categoryID) { int rowsAffected = Adapter.Update (categoryName, description, brochurePath, categoryID); // Return true if precisely one row was updated, otherwise false return rowsAffected == 1; } 

第3步:拷贝功能

  在上一章里,我们创建了一个UploadInDetailsView.aspx页面,在一个GridView控件列出所有的类,再通过一个DetailsView控件来添加新的类。在本教程,我们将扩展GridView控件以支持编辑和删除功能。不过我们不再使用UploadInDetailsView.aspx页面,让我们在~/BinaryData文件夹里创建一个新页面,UpdatingAndDeleting.aspx,将UploadInDetailsView.aspx页面的声明代码复制并粘贴到页面UpdatingAndDeleting.aspx.

  打开UploadInDetailsView.aspx页面,将其元素里的声明代码复制下来,就像图3那样。接下来,打开UpdatingAndDeleting.aspx页面,把代码粘贴在元素里。同样的,将UploadInDetailsView.aspx页面的后台代码拷贝到UpdatingAndDeleting.aspx。

//img.jbzj.com/file_images/article/201605/2016051710105727.gif
图3:将UploadInDetailsView.aspx页面的声明代码拷贝下来

完成后,登录UpdatingAndDeleting.aspx页面,你将会看到相同的输出效果。感觉用起来和UploadInDetailsView.aspx页面一样。

第4步:添加ObjectDataSource和GridView的删除功能

  就像在教程16《概述插入、更新和删除数据》里探讨的一样,只要GridView控件绑定的数据源支持“删除”功能,我们就可以为GridView控件启用删除功能。不过,GridView控件绑定的ObjectDataSource(也就是CategoriesDataSource)目前并不支持删除。

  为支持删除,在ObjectDataSource的智能标签里点“配置数据源”,一直点到“定义数据方法”界面。虽然当前只指定了ObjectDataSource控件InsertMethod属性和SelectMethod属性,但向导自动地分别为UPDATE标签和DELETE标签指定UpdateCategory方法和DeleteCategory方法。为什么呢?因为我们在CategoriesBLL类里为上述2种方法使用了DataObjectMethodAttribute属性,作用是分别使其成为默认的“更新”和“删除”方法。

  不过现在我们在UPDATE标签的下拉列表里选“(None)”, 而 DELETE标签里仍然为DeleteCategory方法。我们将在第6步添加更新功能。

//img.jbzj.com/file_images/article/201605/2016051710105828.gif
图4:设置ObjectDataSource控件使用DeleteCategory方法

  注意:完成设置后,Visual Studio会问你是否“刷新列和主键”,选择No,因为选择Yes将会把我们自己定制的任何列覆盖掉。

  现在,ObjectDataSource控件将包含DeleteMethod属性和对应的DeleteParameter参数。我们记得在以前的教程提到过,当使用向导指定方法时,Visual Studio会自动的将ObjectDataSource控件的OldValuesParameterFormatString属性设置为original_{0},这将导致更新和删除时出现问题。为此,要么将清除该属性,要么将其设置为默认的{0}值。对该属性的更详细讨论见教程16《概述插入、更新和删除数据

完成后,ObjectDataSource控件的声明代码看起来应该像下面的一样:

设置完ObjectDataSource后,就可以启用GridView的删除功能了,方法是点击其智能标签里的“删除选项”。这将使GridView增加一个CommandField,其ShowDeleteButton属性为true。

//img.jbzj.com/file_images/article/201605/2016051710105829.gif
图5:启用GridView控件的删除功能

  花几分钟测试删除功能。由于表Products和表Categories之间有一个外键CategoryID,当你删除现有的8个类中的任何一个时,你会得到一个外键约束冲突异常。为顺利的实现测试,我们需要添加一个附带图片和说明小册子的新类,如图6所示,小册子为Test.pdf,图7为添加了测试类的GridView控件界面。

//img.jbzj.com/file_images/article/201605/2016051710105830.gif
图6:添加一个附带Brochure和Image文件的测试类

//img.jbzj.com/file_images/article/201605/2016051710105831.gif
图7:添加测试类后,显示在GridView控件里

在Visual Studio里刷新解决资源管理器,你会在文件夹~/Brochures里看到Test.pdf文件(见图8)

下一步,点击Test类的Delete链接,页面回传,引发CategoriesBLL的DeleteCategory 方法,该方法又调用DAL层的Delete方法,向数据库发送适当的DELETE命令。最后数据重新绑定到GridView控件,Test类将不再显示出来。

虽然已经成功地将Test类从Categories表删除,但存储在文件系统的对应小册子仍旧存在,刷新解决资源管理器,你将发现Test.pdf依然放在~/Brochures文件夹里。

//img.jbzj.com/file_images/article/201605/2016051710105832.gif
图8:Test.pdf文件并没有从文件系统删除

第5步:删除残存的Brochure文件

  未将二进制数据存储进数据库时面临的一个问题便是:当删除一条数据库记录时,我们需要另外采取步骤来删除该记录对应的二进制数据文件。当执行delete命令时,会发生一些事前事件和事后事件(pre- and post-action events),我们需要创建对应的事件处理器。在Categories表的记录被删除之前,我们需要确定对应PDF文件的路径,但在删除记录之前我们不会删除其对应的PDF文件,以防发生异常或记录最终未被删除的情况。

  从事件发生的时间先后顺序来看,GridView控件的RowDeleting事件在调用ObjectDataSource控件的delete命令前发生;而RowDeleted事件在调用ObjectDataSource控件的delete命令之后再发生。创建这2个事件处理器,代码如下:

 // A page variable to "remember" the deleted category's BrochurePath value string deletedCategorysPdfPath = null; protected void Categories_RowDeleting(object sender, GridViewDeleteEventArgs e) { // Determine the PDF path for the category being deleted... int categoryID = Convert.ToInt32(e.Keys["CategoryID"]); CategoriesBLL categoryAPI = new CategoriesBLL(); Northwind.CategoriesDataTable categories = categoryAPI.GetCategoryByCategoryID(categoryID); Northwind.CategoriesRow category = categories[0]; if (category.IsBrochurePathNull()) deletedCategorysPdfPath = null; else deletedCategorysPdfPath = category.BrochurePath; } protected void Categories_RowDeleted(object sender, GridViewDeletedEventArgs e) { // Delete the brochure file if there were no problems deleting the record if (e.Exception == null) { // Is there a file to delete? if (deletedCategorysPdfPath != null) { System.IO.File.Delete(Server.MapPath(deletedCategorysPdfPath)); } } } 

  在RowDeleting事件处理器里,从GridView控件的DataKeys集合里获取被删记录的CategoryID值,而在这里,我们通过e.Keys来访问DataKeys集合。接着,调用类CategoriesBLL的GetCategoryByCategoryID(categoryID)方法来返回被删记录的信息,若返回的BrochurePath值不为NULL,那么将其赋值给页面参数deletedCategorysPdfPath,再在RowDeleted事件处理器里删除文件。

  注意:在RowDeleting事件处理器里,我们没有返回被删记录的BrochurePath信息,而是将BrochurePath添加到GridView的DataKeyNames属性,再通过访问e.Keys来获取该记录的值。这样做虽然稍微增大了GridView的视图状态,但减少了必要的代码,也省了一步访问数据库。

  调用ObjectDataSource控件的delete命令后,紧接着发生GridView控件的RowDeleted事件,如果删除过程没有异常且deletedCategorysPdfPath值不为空,那就将对应的PDF文件从文件系统删除。我们注意到,代码没有删除类的picture,那是因为picture数据是直接存储在数据库里的,当删除记录时就一起删除了。

  添加完上述2个事件处理器后,再次测试删除。当删除某个类时,其对应的PDF文件也删除了。

  下面我们深入研究添加更新功能以应对类的brochure和picture.第6步探讨更新brochure信息的技术,第7章探讨更新picture。

<

-六神源码网