在ASP.NET 2.0中操作数据之六十八:为DataTable添加额外的列


导言:

  当向类型化的数据集(Typed DataSet)添加一个TableAdapter时,相应的DataTable的构架已经由TableAdapter的主查询定义好了.比如,如果主查询返回A, B,C这3个域,那么 DataTable将有对应的3个列A, B,和C.除了主查询以外,TableAdapter还可以包含其他的查询,可能是返回基于某些参数的数据。比如,ProductsTableAdapter的主查询返回所有产品的信息,此外,ProductsTableAdapter还包含诸如GetProductsByCategoryID(categoryID) 和 GetProductByProductID(productID)的方法,它们根据指派的参数返回特定的产品信息.

  如果TableAdapter的方法返回的列涵盖在主查询里,工作起来没有问题。但如果返回的列并没有涵盖在主查询,那么我们就需要对DataTable的构架进行扩充.在第35章《使用Repeater和DataList单页面实现主/从报表》里,我们向CategoriesTableAdapter添加方法以返回 CategoryID, CategoryName, Description和NumberOfProducts列。其中前3列是涵盖在主查询里的,而NumberOfProducts列没有在主查询里定义,它返回的是每个category相关产品的数目.我们可以向CategoriesDataTable手工添加一列,以便于统计从新方法返回的NumberOfProducts列的值.

  在第52章《使用FileUpload上传文件》我们探讨过,对使用ad-hoc SQL statements构建且其方法返回的列超出主查询范围的TableAdapters必须多加留意.因为一旦重新运行设置向导的话,它将对TableAdapter的方法进行更新,使其返回的列与主查询相匹配.不过如果使用存储过程的话就不会出现这种情况.

  在本文我们将考察如何扩展DataTable的构架以包含额外的列。我们都知道使用ad-hoc SQL statements构架的TableAdapter不稳定,本文我们将用存储过程来构架.你可以参考第65章《在TableAdapters中创建新的存储过程》和第66章《在TableAdapters中使用现有的存储过程》来获取设置TableAdapter使用存储过程的更多信息.

第一步:向ProductsDataTable添加一个PriceQuartile列

  在第67章里我们创建了一个名为NorthwindWithSprocs的类型化的数据集.该数据集目前包含2个DataTables:ProductsDataTable以及 EmployeesDataTable。其中ProductsTableAdapter包含3个方法:

.GetProducts——主查询,返回Products表的所有记录
.GetProductsByCategoryID(categoryID)——根据指定的categoryID值返回所有产品
.GetProductByProductID(productID)——根据指定的productID值返回所有的产品

  主查询及另外2个方法都返回相同的数据列,也就是Products表的所有列,并没有返回Categories 以及Suppliers表的相关数据.

  在本文,我们将向ProductsTableAdapter添加一个名为GetProductsWithPriceQuartile 的方法,它返回所有的产品.除了标准的数据列外,它还返回PriceQuartile列,它用四分位数来衡量产品价格下跌程度.如果产品价格上升了25%,那么其值为1,如果下降为25%,那么其值为4.在我们创建一个存储过程来返回这种信息之前,我们首先需要更新ProductsDataTable,新添一列来包含GetProductsWithPriceQuartile方法返回的 PriceQuartile值.

  打开NorthwindWithSprocs数据集,在ProductsDataTable上右键单击,选择“ Add” ,再选择“Column”.


图1:向ProductsDataTable新添一列

  这将向DataTable新添一列,名为“Column1”,类型为System.String.我们需要将该列的名称改为“PriceQuartile”,类型改为System.Int32,因为它的值介于1到4之间.在ProductsDataTable 选中我们新添加的列,在属性窗口里设置其Name属性为 “PriceQuartile”,DataType属性为System.Int32.


图2:设置该新列的Name 和 DataType属性

  就像图2所示,我们还可以设置其它的属性.比如,是否该列的值必须为unique;如果该列为自增列,其值是否允许为NULL等等.不过我们这里使用其默认值.

第二步:创建GetProductsWithPriceQuartile方法

  现在我们已经对ProductsDataTable进行了更新以包含PriceQuartile列,我们将要创建一个GetProductsWithPriceQuartile方法.在TableAdapter上单击右键,再选择“Add Query”.这将开启TableAdapter查询设置向导,它首先询问我们是使用ad-hoc SQL statements还是使用现有的存储过程或新建一个存储过程.我们选择“Create new stored procedure”,再点Next.


图3:在TableAdapter向导里创建新的存储过程

  接下来,如图4所示,向导询问我们添加的是那种类型的查询,由于GetProductsWithPriceQuartile方法将返回Products表的所有记录以及所有列,我们选择“SELECT which returns rows”项,再点Next.


图4:查询将是一个返回多个行的SELECT Statement

接下来,我们在向导里键入如下的查询:

SELECT ProductID, ProductName, SupplierID, CategoryID,
 QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
 ReorderLevel, Discontinued,
 NTILE(4) OVER (ORDER BY UnitPrice DESC) as PriceQuartile
FROM Products

  上述查询使用了SQL Server 2005新增的NTILE function函数,它将结果划分为4组,将UnitPrice值按降序分组.

  不幸的是,查询构造器(Query Builder)不能解析关键字OVER,并抛出一个错误信息。因此,直接在向导的文本框里键入上述代码,而不要使用查询构造器.

  注意:关于NTILE以及SQL Server 2005的其它函数的更多信息,你可参阅文章《Returning Ranked Results with Microsoft SQL Server 2005》(基于数据的自定义格式化》

另一种途径——创建另一个TableAdapter

  正如我们在本文看到的,当向TableAdapter添加的方法返回的列超出了主查询范围的时候,我们可以向DataTable添加相应的列即可.对TableAdapter而言,如果当其包含的返回“额外列”的方法较少且“额外列”不是很多的时候,这种途径才能正常工作。

  除了往DataTable添加列以外,我们还可以对DataSet添加另外的TableAdapter,其包含的方法就是那些需要返回“额外列”的方法.就本问而言,我们可以向DataSet添加另一个名为ProductsWithPriceQuartileTableAdapter的TableAdapter,它将Products_SelectWithPriceQuartile存储过程作为它的主查询,对要获取price quartile信息的ASP.NET页面来说,只需调用 ProductsWithPriceQuartileTableAdapter即可;而不需要获取price quartile信息的页面只需要调用ProductsTableAdapter即可.

  这种另外新添加的TableAdapters可能导致某些功(functionality)、作业(task)重复.比如,如果那些展示PriceQuartile列的页面也要启用insert, update,delete功能的话,那么就要对ProductsWithPriceQuartileTableAdapter的InsertCommand, UpdateCommand,DeleteCommand属性进行适当的设置.而我们已经对ProductsTableAdapter的这3个属性进行过设置了,这时就有2种方法来对数据库里的产品进行添加、更新、删除操作了——使用ProductsTableAdapter类或 ProductsWithPriceQuartileTableAdapter类.

  本文供下载的代码里,在NorthwindWithSprocs数据集里包含了ProductsWithPriceQuartileTableAdapter class类,演示了这2种方法.

总结:

  在大多数情况下,TableAdapter的所有方法返回的数据列都是相同的,但有极少数方法会返回主查询没有包含的“额外列”.比如我们在第35章《使用Repeater和DataList单页面实现主/从报表》里,我们向CategoriesTableAdapter添加了一个方法,该方法除了返回主查询里的列外,还返回了一个NumberOfProducts列.而在本文,我们考察类了向 ProductsTableAdapter 添加一个方法以返回一个没有包含在主查询里的PriceQuartile列.对这种返回来的“额外列”,我们需要向DataTable添加一个对应的列.

  如果你打算手工向DataTable添加列,我们建议一使用存储过程.如果用ad-hoc SQL statements的话,任何时候只要重新运行TableAdapter设置向导,用户所做的所有定制都要被覆盖.而用存储过程的话就不会出现这种情况.

  祝编程快乐!

作者简介

  本系列教程作者 Scott Mitchell,著有六本ASP/ASP.NET方面的书,是4GuysFromRolla.com的创始人,自1998年以来一直应用 微软Web技术。大家可以点击查看全部教程《[翻译]Scott Mitchell 的ASP.NET 2.0数据教程》,希望对大家的学习ASP.NET有所帮助。


« 
» 
快速导航

Copyright © 2016 phpStudy | 豫ICP备2021030365号-3