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

在ASP.NET 2.0中操作数据之五十四:添加新记录时包含一个文件上传选项_自学过程_

2023-05-24 352人已围观

简介 在ASP.NET 2.0中操作数据之五十四:添加新记录时包含一个文件上传选项_自学过程_

导言:

  在前面2节教程,我们探讨了如何使用FileUpload控件从客户端向服务器上传文件,以及如何在数据Web控件里显示二进制数据。

  在本节,我们将创建一个web页面以添加新的种类。除了为类的name和description属性添加TextBoxes控件外,我们还要在页面上添加2个FileUpload控件——一个用来上传新类的图片,另一个用来上传类的小说明册子。上传的图片将直接存储在新记录的Picture列。与此相反,小册子将存储在~/Brochures 文件夹,同时将文件路径存储在新记录的BrochurePath列。

  在创建页面之前,我们需要更新体系结构。由于CategoriesTableAdapter的主查询并不返回Picture列,因此自动生产的Insert方法只包含了CategoryName, Description和BrochurePath列。我们需要在TableAdapter里创建新的方法以包括Categories的4个列。同时业务逻辑层的的CategoriesBLL类也需要更新。

第1步:在CategoriesTableAdapter添加一个InsertWithPicture方法

  在前面的教程《创建一个数据访问层》里我们创建了CategoriesTableAdapter,并设置其自动生成了基于主查询的INSERT, UPDATE和DELETE命令。此外,我们设置该TableAdapter启用DB Direct方法,它将创建Insert, Update和Delete方法。这些方法执行自动生成的INSERT, UPDATE和DELETE命令,自然而然的,其接受的输入参数基于主查询所返回的那些列。在教程《使用FileUpload上传文件》里,我们扩展了 CategoriesTableAdapter的主查询以包含BrochurePath列。

  因为CategoriesTableAdapter的主查询并为引用Picture,在添加新记录或更新记录时不能涉及Picture值。为了获取Picture信息,我们要么在TableAdapter里创建一个新方法以插入Picture的二进制数据;要么定制自动生成的INSERT命令。但定制自动生成的INSERT命令有一个风险,即定制的INSERT命令有可能被向导覆盖。比如,假设我们定制INSERT命令使用Picture列,更新TableAdapter的Insert方法,使之多包含一个对应picture二进制数据的参数。然后在业务逻辑层创建一个方法使用该 DAL方法,再在表现层调用该业务逻辑层方法。现在一切工作正常,但当下一次在TableAdapter设置向导里设置TableAdapter完成后,我们定制的INSERT命令马上就会被向导重写,回归到定制前的状态。其结果是我们的代码将无法编译!

  注意:如果使用存储过程而不用SQL语句的话,就不存在这个问题。在以后的教程里,我们将探讨在数据访问层用存储过程替代SQL语句。

  为避免这个头痛的问题,我们为TableAdapter添加新的方法,而不定制自动生成的SQL命令。我们为添加的方法命名为InsertWithPicture,它接受 CategoryName, Description, BrochurePath和Picture值;执行INSERT命令将上述值添加进一条记录。

  在CategoriesTableAdapter的顶部点右键,选择“添加查询”。进入TableAdapter 查询设置向导,首先询问我们TableAdapter查询如何访问数据库,选择“使用SQL语句”,点Next,因为我们要为表Categories添加新记录,选“INSERT”,点Next。

//img.jbzj.com/file_images/article/201605/2016051709451314.gif
图1:选“INSERT”选项

  现在,我们需要指定INSERT SQL语句。向导自动地生成一个基于主查询的INSERT语句。此时,它只插入CategoryName, Description和BrochurePath值。对其更新,包括Picture列和参数@Picture ,如下:

 INSERT INTO [Categories] ([CategoryName], [Description], [BrochurePath], [Picture]) VALUES (@CategoryName, @Description, @BrochurePath, @Picture)

最后,向导要我们为方法命名,取名为InsertWithPicture,点Finish。

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

第2步:更新业务逻辑层

  由于一般来说表现层将引用业务逻辑层,而不是绕过它直接引用数据访问层,我们需要创建一个业务逻辑层方法,以调用刚才创建的数据访问层方法(InsertWithPicture),本节,我们在CategoriesBLL里创建一个名为InsertWithPicture方法,它接受3个字符串和一个byte数组,字符串参数对应name, description和brochure文件地址;byte数组对应于图片的二进制内容。就像下面的代码所显示的那样,BLL方法调用相应DAL方法:

 [System.ComponentModel.DataObjectMethodAttribute (System.ComponentModel.DataObjectMethodType.Insert, false)] public void InsertWithPicture(string categoryName, string description, string brochurePath, byte[] picture) { Adapter.InsertWithPicture(categoryName, description, brochurePath, picture); }

  注意:在为BLL添加InsertWithPicture方法前,确保已经保存了数据集(Typed DataSet ),因为CategoriesTableAdapter类的代码是基于Typed DataSet自动生成的。如果最开始没有把对Typed DataSet所进行的修改保存的话,Adapter属性将不认同InsertWithPicture方法。

第3步:列出现有的种类及其二进制数据

  本教程我们将创建一个页面,允许用户添加新的类,包含其图片和说明小册子。在上一节,我们用一个包含TemplateField和ImageField的GridView控件来展示每个类的名称、描述,并包含一个下载说明小册子的链接。在本教程,我们实现相同的功能,创建一个页面,即展示现有的类,还可以添加新的类。

  打开BinaryData文件夹的DisplayOrDownload.aspx页面,切换到源模式,复制GridView和ObjectDataSource控件的声明代码,粘贴在UploadInDetailsView.aspx页面的元素里。同时不要忘记将后台代码类的GenerateBrochureLink方法拷贝到UploadInDetailsView.aspx的后台代码类里。

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

  完成以后,在浏览器里查看该页面,确保一切正常。GridView控件里列出了8个类,每个类包含一张图片以及一个下载说明小册子的链接。

//img.jbzj.com/file_images/article/201605/2016051709451317.gif
图4:你应该看到每个类及其相应二进制数据

第4步:设置CategoriesDataSource以支持添加功能

  那个ID为Categories的GridView控件所使用的名为CategoriesDataSource的 ObjectDataSource控件目前还不支持添加数据。为实现该功能,我们要设置该控件的Insert方法引用类CategoriesBLL的某个方法。具体的讲,我们要用到在第2步里添加的InsertWithPicture方法。

  在ObjectDataSource控件的智能标签里,点“设置数据源”。照原样一直点到“Define Data Methods”界面。再点INSERT标签,从下拉列表里选方法“InsertWithPicture”,点Finish完成设置。

//img.jbzj.com/file_images/article/201605/2016051709451418.gif
图5:设置ObjectDataSource控件使用InsertWithPicture方法

  注意:当完成设置后,Visual Studio会问你是否“刷新Fields and Keys”,选择No,因为如果选Yes的话,将重新构造data Web controls fields,那样将重写所有我们已经定制好的列(field)。

完成设置后,ObjectDataSource控件将会为InsertMethod属性赋值,同时包含一个,如下面的声明代码所示:

第5步:创建一个插入界面

  在教程16《概述插入、更新和删除数据》里我们谈到,当DetailsView控件的数据源控件支持添加功能时,便可以启用DetailsView内置的添加界面。让我们在页面上添加一个DetailsView控件,置于GridView控件之上,并处于添加模式。当在DetailsView控件里添加一个新种类时,其下的GridView控件将自动发生刷新,并将刚添加的类显示出来。

  从工具箱拖一个DetailsView控件到页面,置于GridView之上,设其ID为NewCategory,清空其Height和Width属性。 其智能标签里,设置它绑定到名为CategoriesDataSource的数据源,并启用“插入”功能。

//img.jbzj.com/file_images/article/201605/2016051709451419.gif
图6:将DetailsView控件绑定到CategoriesDataSource,并启用插入功能。

  为使DetailsView呈现为插入界面,设其DefaultMode属性为Insert

  我们注意到,尽管DetailsView控件有5个BoundFields——CategoryID, CategoryName, Description, NumberOfProducts和BrochurePath,但插入界面并不包含CategoryID,因为CategoryID列的InsertVisible属性为false。为什么会显示这4个列呢?因为ObjectDataSource调用的GetCategories()方法返回的就是这些列。当添加新类时,我们不希望用户为NumberOfProducts列指定值,此外,我们还希望让用户为新类上传图片和相关的PDF小册子。

  在DetailsView里将NumberOfProducts列完成删除,再分别CategoryName列和BrochurePath列的HeaderText属性设置为“Category”和“Brochure”。将BrochurePath 转换为TemplateField,再添加一个TemplateField,设其HeaderText属性为“Picture”,把它放置在BrochurePath列和CommandField列之间。

//img.jbzj.com/file_images/article/201605/2016051709451420.gif
图7:将DetailsView控件绑定到CategoriesDataSource,并启用插入功能(注:图片说明有误)

  当你在“编辑列”对话框里将BrochurePath BoundField 转换为一个TemplateField后,该TemplateField将包含3个模板:ItemTemplate,EditItemTemplate和InsertItemTemplate,由于我们只需要InsertItemTemplate模板,将另外2个模板删除。如此,你的DetailsView控件的声明代码看起来应该像下面的这样:

为Brochure和Picture Fields添加FileUpload控件

  当前,BrochurePath TemplateField的InsertItemTemplate模板包含一个TextBox,而Picture TemplateField并不包含任何的模板,我们为这2个TemplateField的InsertItemTemplate模板模板添加FileUpload控件。

  从DetailsView控件的智能标签选择“编辑模板”,从下拉列表选择BrochurePath TemplateField的InsertItemTemplate模板,将模板里的TextBox删除,从工具箱拖一个FileUpload控件到页面,设其ID为BrochureUpload。类似的,为Picture TemplateField的InsertItemTemplate模板添加一个ID为PictureUpload的FileUpload控件。

//img.jbzj.com/file_images/article/201605/2016051709451421.gif
图8:在InsertItemTemplate模板里添加一个FileUpload控件

完成添加后,这2个TemplateField的声明代码应该和下面的差不多:

  当用户添加一个新类时,我们希望确保上传的图片和说明小册子是恰当的文件类型。对说明小册子,必须是PDF类型;对图片,我们需要用户上传一个image文件。那是不是image文件必须是某个特定的类型呢,比如GIF或JPG?考虑到其它不同类型的文件,我们需要扩展表Categories的列以包含这些类型的文件,同时我们可以在页面DisplayCategoryPicture.aspx里通过Response.ContentType将这些文件发送到客户端。由于表Categories现在并没有这样的列,我们只有限制用户上传指定为某种类型的image文件。表Categories里现有的images为位图,不过使用JPG类型或许更恰当。

  当用户上传的文件类型不正确时,我们将取消插入操作,并显示一个提示信息。在DetailsView控件下添加一个Label Web控件,设ID为UploadWarning,清除Text属性,设CssClass属性为“Warning”, 再将Visible和EnableViewState属性都设为false。Warning CSS定义在Styles.css里,作用是将文字显示为粗斜体,红色大号字。

  注意:最理想的情况是将CategoryName和Description BoundFields都转换为TemplateFiel

-六神源码网