|
|
4#

楼主 |
发表于 2008-5-23 13:25:49
|
只看该作者

![]()
图 5: 外层的Repeater 列出每个Category; 内层的Repeater 列出属于Category的Products
直接编程来获取Category 下的Products
除了使用ObjectDataSource来获取当前category下的proudct外,我们还可以在ASP.NET页的code-behind里(或App_Code文件夹里或一个单独的类项目里)来创建一个根据传入的CategoryID返回合适的product集的方法.假设在ASP.NET页的code-behind里有一个名为GetProductsInCategory(categoryID)方法.我们可以使用这个方法来将当前category下的product绑定到内层的Repeater.见下面的代码:
ASP.NET
<asp:Repeater runat="server" ID="ProductsByCategoryList" EnableViewState="False"
DataSource='<%# GetProductsInCategory(CType(Eval("CategoryID"), Integer)) %>'>
...
</asp:Repeater>
Repeater的DataSource属性通过绑定语法来指定它的数据是通过GetProductsInCategory(categoryID)得到.由于Eval("CategryID")返回的是Object类型,我们在它传入GetProductsInCategory(categoryID)前将它转化成Integer.注意这里的CategoryID是通过外层Repeater(CategoryList)的CategoryID(已经绑定到Categories table)获取的.因此它不可能是一个NULL值.所以我们在绑定前没有检查.
我们现在需要创建GetProductsInCategory(categoryID)方法.在这里简单使用ProductsBLL类的GetProductsByCategoryID(categoryID)方法返回的ProductsDataTable就可以了.我们在NestedControls.aspx页的code-behind里创建GetProductsInCategory(categoryID).见下面的代码:
C#
protected Northwind.ProductsDataTable GetProductsInCategory(int categoryID)
{
// Create an instance of the ProductsBLL class
ProductsBLL productAPI = new ProductsBLL();
// Return the products in the category
return productAPI.GetProductsByCategoryID(categoryID);
}
这个方法仅仅是创建一个ProductsBLL实例然后返回GetProductsByCategoryID(categoryID)方法的返回值.注意这个方法必须标记为Public或Protected.如果标记为Private,ASP.NET页的声明标记里将不能调用它.
做完以上操作后,在浏览器里浏览页面.页面看起来应该和使用ObjectDataSource 和ItemDataBound event handler方法差不多(图5).
注意:在ASP.NET页的code-behind里创建GetProductsInCategory(categoryID)方法好象只是一个形式,毕竟这个方法只是调用BLL里的方法.为什么不直接在内层Repeater里的绑定语法里直接调用这个方法.比如:
DataSource='<%#ProductsBLL.GetProductsByCategoryID(CType(Eval("CategoryID"),Integer))%>')
虽然这个声明是不起作用的(因为GetProductsByCategoryID(categoryID)方法是一个实例方法),你可以修改ProductsBLL来包含一个这样的静态方法.
这样的修改可以满足ASP.NET页的GetProductsInCategory(categoryID)方法的需要,但是写在code-behind里可以更灵活的获取数据,我们在后面会看到这点.
获取所有的Product 信息
前面两个方法我们通过调用ProductsBLL类的GetProductsByCategoryID(categoryID)方法来获取当前category的product(第一种通过ObjectDataSource,第二种通过GetProductsInCategory(categoryID)).每次方法被调用时,BLL调用DAL,DAL通过SQL查询数据库,返回特定的记录.
如果有N个category,这个方法会访问数据库N+1次— 一次返回所有的category,N次返回特定category下的product.然而我们可以通过访问数据库两次来获取所有需要的数据— 一次返回所有的category,一次返回所有的product.一旦我们得到所有的product,我们可以根据CategoryID来过滤,然后再绑定.
我们只需要稍微修改ASP.NET页的code-behind里的GetProductsInCategory(categoryID)方法来实现这个功能.我们首先来返回所有的product,然后根据传入的CategoryID里过滤.
C#
private Northwind.ProductsDataTable allProducts = null;
protected Northwind.ProductsDataTable GetProductsInCategory(int categoryID)
{
// First, see if we've yet to have accessed all of the product information
if (allProducts == null)
{
ProductsBLL productAPI = new ProductsBLL();
allProducts = productAPI.GetProducts();
}
// Return the filtered view
allProducts.DefaultView.RowFilter = "CategoryID = " + categoryID;
return allProducts;
}
注意allProducts变量.它在第一次调用GetProductsInCategory(categoryID)时返回所有product信息.确定allProducts对象被创建后,在根据CategoryID来对DataTable过滤.这个方法将访问数据库的次数从N+1减少到2次.
这个改进没有修改页面的声明语言.仅仅只是减少了数据库的访问次数.
注意:可能想当然的觉得减少了数据库访问次数会提高性能.但是这个不一定.如果你有大量的categoryID为NULL的product,这样使用GetProducts方法返回的product有一部分不会被显示.而且如果你只需要显示一部分category的proudct(分页时就是这样),而返回所有的product,这样对资源也是一种浪费.
通常对两种技术进行性能分析,唯一正确的方法是设置程序常见的场景来进行压力测试.
总结
本章我们学习了如何嵌套Web控件.通过如何在外层Repeater显示各个category,内层Repeater显示每个category下的product来作为例子.主要的任务在于获取正确的数据并绑定到内层的Web控件上.有很多方法可以使用,我们这里讨论了两种.第一种是使用在外层控件的ItemTemplate里ObjectDataSource来绑定到内层控件.第二种是使用ASP.NET页的code-behind里的方法.它通过内层控件的DataSource属性来绑定.
本章使用的控件是Repeater,也可以将Repeater嵌套在GridView里,或GridView嵌套在DataList里等.
祝变成快乐! |
|