六十八为DataTable添加额外的列.docx
《六十八为DataTable添加额外的列.docx》由会员分享,可在线阅读,更多相关《六十八为DataTable添加额外的列.docx(15页珍藏版)》请在冰豆网上搜索。
![六十八为DataTable添加额外的列.docx](https://file1.bdocx.com/fileroot1/2022-12/29/e41ceacf-fa04-42c6-81da-d72398650999/e41ceacf-fa04-42c6-81da-d723986509991.gif)
六十八为DataTable添加额外的列
在ASP.NET2.0中操作数据之六十八:
为DataTable添加额外的列
作者:
heker2007字体:
[增加 减小]类型:
转载时间:
2016-05-19 我要评论
本文介绍并使用TableAdapter向DataTable添加新的一列的方法和步骤,任何时候只要重新运行TableAdapter设置向导,用户所做的所有定制都要被覆盖,为避免出现这种情况,我们建议直接修改存储过程。
导言:
当向类型化的数据集(TypedDataSet)添加一个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-hocSQLstatements构建且其方法返回的列超出主查询范围的TableAdapters必须多加留意.因为一旦重新运行设置向导的话,它将对TableAdapter的方法进行更新,使其返回的列与主查询相匹配.不过如果使用存储过程的话就不会出现这种情况.
在本文我们将考察如何扩展DataTable的构架以包含额外的列。
我们都知道使用ad-hocSQLstatements构架的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上单击右键,再选择“AddQuery”.这将开启TableAdapter查询设置向导,它首先询问我们是使用ad-hocSQLstatements还是使用现有的存储过程或新建一个存储过程.我们选择“Createnewstoredprocedure”,再点Next.
图3:
在TableAdapter向导里创建新的存储过程
接下来,如图4所示,向导询问我们添加的是那种类型的查询,由于GetProductsWithPriceQuartile方法将返回Products表的所有记录以及所有列,我们选择“SELECTwhichreturnsrows”项,再点Next.
图4:
查询将是一个返回多个行的SELECTStatement
接下来,我们在向导里键入如下的查询:
?
1
2
3
4
5
SELECTProductID,ProductName,SupplierID,CategoryID,
QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder,
ReorderLevel,Discontinued,
NTILE(4)OVER(ORDERBYUnitPriceDESC)asPriceQuartile
FROMProducts
上述查询使用了SQLServer2005新增的NTILEfunction函数,它将结果划分为4组,将UnitPrice值按降序分组.
不幸的是,查询构造器(QueryBuilder)不能解析关键字OVER,并抛出一个错误信息。
因此,直接在向导的文本框里键入上述代码,而不要使用查询构造器.
注意:
关于NTILE以及SQLServer2005的其它函数的更多信息,你可参阅文章《ReturningRankedResultswithMicrosoftSQLServer2005》(Server2005BooksOnline的《RankingFunctionssection》部分(
完成后,点Next,向导将要我们为新存储过程重命名,我们取名为Products_SelectWithPriceQuartile再点Next.
图5:
将新存储过程命名为Products_SelectWithPriceQuartile
最后我们要为TableAdapter的方法命名,选中“FillaDataTable”和“ReturnaDataTable”两项,并重命名为FillWithPriceQuartile和GetProductsWithPriceQuartile.
图6:
对TableAdapter的方法命名并点Finish
当指定了SELECT查询,并对存储过程和TableAdapter的方法命名后,点Finish完成向导。
这时你将看到1到2条警告信息,说“TheOVERSQLconstructorstatementisnotsupported.”不必理会它.
完成向导后,该TableAdapter将会包含FillWithPriceQuartile和GetProductsWithPriceQuartile方法,并且数据库将包含一个名为Products_SelectWithPriceQuartile的存储过程。
花点时间来验证一下,检查数据库,如果你没有看到我们刚添加的存储过程,在存储过程文件夹上右键单击,选“刷新”.
图7:
验证新方法是否添加到TableAdapter
图8:
确保数据库包含Products_SelectWithPriceQuartile存储过程
注意:
使用存储过程来替换ad-hocSQLstatements的好处之一是重新运行TableAdapter设置向导的话并不会改动存储过程返回的列.我们可以作一个验证,在TableAdapter上右键单击,选“Configure”项,以启动向导,然后点Finish完成向导。
接下来,我们在数据库里查看Products_SelectWithPriceQuartile存储过程.我们注意到其返回的列并没有发生变化.如果我们使用的是ad-hocSQLstatements的话,重新运行向导将会使查询返回的列与主查询的列相匹配,因此它将把GetProductsWithPriceQuartile方法里使用的查询里的NTILEstatement删除掉.
当调用数据访问层的GetProductsWithPriceQuartile方法时,TableAdapter将执Products_SelectWithPriceQuartile存储过程,并为返回的每条记录向ProductsDataTable添加对应的row.存储过程返回的数据域(datafields)将映射到ProductsDataTable的列.因为该存储过程要返回一个PriceQuartile数据域,所以它的值将分配给ProductsDataTable的PriceQuartile列.
对于那些不返回PriceQuartile数据域的方法而言,PriceQuartile列的值由其DefaultValue属性指定.如图2所示,该默认值为DBNull。
如果你想指定为其他值,仅仅改动DefaultValue属性即可,但一定要是一个有效的值(比如,PriceQuartile列的值一定要是一个System.Int32类型的值).
现在我们完成了向DataTable添加额外列的必要的步骤,接下来我们要创建一个ASP.NET页面来展示每个产品的name,price,以及pricequartile.不过我们要先对业务逻辑层进行更新,以包含一个方法来调用数据访问层的GetProductsWithPriceQuartile方法.我们将在第3步更新业务逻辑层,在第4步创建一个ASP.NET页面.
第三步:
更新业务逻辑层
我们在表现层调用新添加的GetProductsWithPriceQuartile方法以前,必须在业务逻辑层添加相应的方法,打开ProductsBLLWithSprocsclass类文件,添加如下的代码:
?
1
2
3
4
5
6
[System.ComponentModel.DataObjectMethodAttribute
(System.ComponentModel.DataObjectMethodType.Select,false)]
publicNorthwindWithSprocs.ProductsDataTableGetProductsWithPriceQuartile()
{
returnAdapter.GetProductsWithPriceQuartile();
}
就像其它方法一样,GetProductsWithPriceQuartile仅仅调用数据访问层对应的GetProductsWithPriceQuartile方法并返回其结果.
第四步:
在一个ASP.NET页面展示PriceQuartile信息
完成对业务逻辑层的修改后,我们将创建一个ASP.NET页面来显示每个产品的pricequartile信息.打开AdvancedDAL文件夹里的AddingColumns.aspx页面,从工具箱拖一个GridView控件到页面,设置其ID为Products.在其智能标签里将其绑定到一个名为ProductsDataSource的新的ObjectDataSource控件,设置该控件调用ProductsBLLWithSprocsclass类的GetProductsWithPriceQuartile方法,在UPDATE,INSERT,和DELETE标签里选“(None)”.
图9:
设置ObjectDataSource调用ProductsBLLWithSprocs类
图10:
调用GetProductsWithPriceQuartile方法获取产品信息
完成设置向导后,VisualStudio会为GridView添加BoundField或CheckBoxField列,其中包括PriceQuartile列.将ProductName,UnitPrice,PriceQuartile以外的列全部删除,设置UnitPrice列为货币格式.并将UnitPrice和PriceQuartile列放在右边,居中。
最后分别将这3列的HeaderText属性设置为“Product”,“Price”,“PriceQuartile”。
同时启用GridView控件的排序功能.
作上述修改后,GridView和ObjectDataSource控件的声明代码看起来和下面的差不多:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
GridViewID="Products"runat="server"AllowSorting="True"
AutoGenerateColumns="False"DataKeyNames="ProductID"
DataSourceID="ProductsDataSource">
BoundFieldDataField="ProductName"HeaderText="Product"
SortExpression="ProductName"/>
BoundFieldDataField="UnitPrice"DataFormatString="{0:
c}"
HeaderText="Price"HtmlEncode="False"
SortExpression="UnitPrice">
BoundField>
BoundFieldDataField="PriceQuartile"HeaderText="PriceQuartile"
SortExpression="PriceQuartile">
BoundField>
GridView>
ObjectDataSourceID="ProductsDataSource"runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProductsWithPriceQuartile"
TypeName="ProductsBLLWithSprocs">
ObjectDataSource>
如图11为在浏览器里登录该页面的情况,我们注意到,最开始产品按price的降序排列,同时每个产品都有相应的PriceQuartile值,当然这些数据也可以按其它标准来排序,如图12所示。
图11:
产品按Prices来排序
图12:
产品按名称来排序.
注意:
只需要很少的代码,我们就可以根据每行PriceQuartile值的不同而显示不同的颜色,比如对值为1的行显示为浅绿色,对值为2的行显示为浅黄色,以此类推.你可以花点时间来实现该功能,如果有必要的话,你可以参阅第11章《基于数据的自定义格式化》
另一种途径——创建另一个TableAdapter
正如我们在本文看到的,当向TableAdapter添加的方法返回的列超出了主查询范围的时候,我们可以向DataTable添加相应的列即可.对TableAdapter而言,如果当其包含的返回“额外列”的方法较少且“额外列”不是很多的时候,这种途径才能正常工作。
除了往DataTable添加列以外,我们还可以对DataSet添加另外的TableAdapter,其包含的方法就是那些需要返回“额外列”的方法.就本问而言,我们可以向DataSet添加另一个名为ProductsWithPriceQuartileTableAdapter的TableAdapter,它将Products_SelectWithPriceQuartile存储过程作为它的主查询,对要获取pricequartile信息的ASP.NET页面来说,只需调用ProductsWithPriceQuartileTableAdapter即可;而不需要获取pricequartile信息的页面只需要调用ProductsTableAdapter即可.
这种另外新添加的TableAdapters可能导致某些功(functionality)、作业(task)重复.比如,如果那些展示PriceQuartile列的页面也要启用insert,update,delete功能的话,那么就要对ProductsWithPriceQuartileTableAdapter的InsertCommand,UpdateCommand,DeleteCommand属性进行适当的设置.而我们已经对ProductsTableAdapter的这3个属性进行过设置了,这时就有2种方法来对数据库里的产品进行添加、更新、删除操作了——使用ProductsTableAdapter类或ProductsWithPriceQuartileTableAdapter类.
本文供下载的代码里,在NorthwindWithSprocs数据集里包含了ProductsWithPriceQuartileTableAdapterclass类,演示了这2种方法.
总结:
在大多数情况下,TableAdapter的所有方法返回的数据列都是相同的,但有极少数方法会返回主查询没有包含的“额外列”.比如我们在第35章《使用Repeater和DataList单页面实现主/从报表》里,我们向CategoriesTableAdapter添加了一个方法,该方法除了返回主查询里的列外,还返回了一个NumberOfProducts列.而在本文,我们考察类了向ProductsTableAdapter添加一个方法以返回一个没有包含在主查询里的PriceQuartile列.对这种返回来的“额外列”,我们需要向DataTable添加一个对应的列.
如果你打算手工向DataTable添加列,我们建议一使用存储过程.如果用ad-hocSQLstatements的话,任何时候只要重新运行TableAdapter设置向导,用户所做的所有定制都要被覆盖.而用存储过程的话就不会出现这种情况.