在 GridView 中显示大量数据并实现搜索功能






4.79/5 (24投票s)
本文介绍了如何在 ASP.NET 3.5 中的 GridView 中显示大量数据并实现搜索功能。
第一部分

引言
本文介绍了如何在 ASP.NET 3.5 中的 GridView
中显示数千甚至数百万条数据。
在第一部分,我们的主要目标是在 gridview
显示大量数据时实现超快的性能。当用户导航数据时,他们不应该感觉自己在导航数百万条数据。
在第二部分,我们将实现 GridView
上的搜索功能。
为了实现这一目标,我们将利用自定义分页、缓存和 AJAX。我们还将在这一部分实现排序。我使用了 SQL Server 2008 的 AdventureWorks
示例数据库。
背景
需要具备 ASP.NET 3.5、C#、自定义分页、GridView
、缓存、AJAX、SQL Server 2008 和 VS 2008 的基础知识。
除此外,我还使用了 DataPager
和 GridView
进行自定义分页。最初,您不能直接将 DataPager
与 GridView
一起使用,因为 DataPager
可与实现 IPageableItemContainer 接口的控件一起使用。因此,我们需要创建一个派生自 GridView
并实现 IPageableItemContainer 的新自定义控件。
有关更多信息,请访问 此处。
概述
让我们先来理解整个流程。当 GridView
首次显示时,我们将检查数据是否已缓存。如果未缓存,我们将从数据库中获取所有记录并存储在缓存中。
我们将根据页索引和每页记录数显示有限数量的记录。我们将按如下方式计算自定义分页的 StartingRowIndex
和 MaximumRecords
:
StartingRowIndex = (PageIndex -1)*PageSize;
MaximumRecords = PageSize.
如果页索引是 1
,每页记录数是 10
,则 startingRowIndex
将是 0
,MaximumRecords
将是 10
,因此我们将从 0 到 9 返回 datatable
中的 10
行。同样,如果页索引是 2
,每页记录数是 10
,则 startingRowIndex
将是 10
,MaximumRecords
将是 10
,因此我们将从 datatable
中从第 10 行到第 19 行返回 10
行。
所以,每次我们只绑定 10
条记录到 GridView
,但我们将根据数据库中的总记录数显示页码。这就是自定义分页和 DataPager
发挥作用的地方。
Using the Code
该项目中有两个独立的层:
- UI
- 数据访问层
我在同一项目的一个不同文件夹中创建了 DAL,但如果您愿意,可以为 DAL 创建一个单独的项目。即使您想将其制作成三层应用程序,也可以为 UI 和 DAL 链接的业务层创建一个单独的项目。但为了简单起见,我在同一个项目中创建了 DAL。
那么,让我们一步一步地开始我们的旅程。
步骤 1:首先在 VS 2008 中创建一个 Web 应用程序项目。保留所有设置不变。我们将使用 GridView
和 DataPager
。因此,我们需要创建一个派生自 GridView
类并实现 IPageableItemContainer
的服务器控件。请访问 此处 以更好地理解,因为本文不是关于将 datapager
与 GridView
一起使用。
步骤 2:创建 GridView
服务器控件后,让我们创建数据访问层。我在 SQL Server 2008 中使用了 AdvantureWorks
示例数据库。因此,您可以下载此示例数据库来运行示例代码。
为数据访问层添加一个新文件夹“DAL”。添加一个名为“AdvWorksDB
”的新类。我们将从 AdvantureWorks
数据库中的 DimCustomer
表获取客户数据。此表有超过 18000 条记录。
AdvWorksDB
类将有两个函数:
GetCustomerSortedPage
GetCustomersCount
请记住一件事,我们处理的是大量数据。因此,为了提高性能,我们不能一次性获取所有记录并将其绑定到 gridview
。如果这样做,您的页面将崩溃。因此,我们将获取 gridview
特定页面的数据,例如 10、25、50 条记录。因此,在任何时候,我们都只获取有限的记录并将其绑定到 grid,假设每页记录数为 pagesize
时为 10 条记录。
private const string CUSTOMER_CACHE_KEY = "CUSTOMER_DATA";
private const string CUSTOMERCOUNT_CACHE_KEY = "CUSTOMER_COUNT";
public static DataTable GetCustomersSortedPage
(int maximumRows, int startRowIndex,
string sortExpression, string searchCriteria)
{
if (string.IsNullOrEmpty(sortExpression))
sortExpression = "customerkey";
try
{
if (AdvWorksDBCache.isRecordsCached(CUSTOMER_CACHE_KEY))
return AdvWorksDBCache.GetData
(CUSTOMER_CACHE_KEY, startRowIndex + 1,
maximumRows, sortExpression, searchCriteria);
SqlConnection dbConnection = new SqlConnection
(ConfigurationManager.ConnectionStrings["SQLDBConString"].ToString());
string sql = "select Cust.*,G.City from
DimCustomer Cust inner join DimGeography G on
G.GeographyKey = Cust.GeographyKey ";
SqlCommand custCommand = new SqlCommand(sql, dbConnection);
custCommand.CommandType = CommandType.Text;
SqlDataAdapter ad = new SqlDataAdapter(custCommand);
DataTable dtCustomers = new DataTable();
ad.Fill(dtCustomers);
dbConnection.Close();
//Cache records
AdvWorksDBCache.Add(CUSTOMER_CACHE_KEY,dtCustomers);
}
catch (Exception e)
{
throw;
}
return AdvWorksDBCache.GetData(CUSTOMER_CACHE_KEY, startRowIndex + 1,
maximumRows, sortExpression, null);
}
在此函数中,我们首先检查数据是否已缓存?如果数据未缓存,我们将获取所有记录并将其添加到缓存中,然后从缓存中返回一部分记录。AdvWorksDBCache
是一个用于缓存的类。我们很快就会看到它。
第二个函数是 GetCustomersCount
,它返回 DimCustomer
表中的记录数。
public static int GetCustomersCount(string searchCriteria)
{
int custCount = 0;
try
{
SqlConnection dbConnection = new SqlConnection
(ConfigurationManager.ConnectionStrings["SQLDBConString"].ToString());
string sql = "select count(*) from DimCustomer ";
if (!string.IsNullOrEmpty(searchCriteria))
sql = sql + " where " + searchCriteria;
SqlCommand sqlCommand = new SqlCommand(sql, dbConnection);
sqlCommand.Connection = dbConnection;
dbConnection.Open();
sqlCommand.CommandType = CommandType.Text;
custCount = Convert.ToInt32(sqlCommand.ExecuteScalar());
dbConnection.Close();
if (AdvWorksDBCache.Get(CUSTOMERCOUNT_CACHE_KEY) != null)
{
// remove customers data if customers count has changed
// since first cache
if (Convert.ToInt32(AdvWorksDBCache.Get(CUSTOMERCOUNT_CACHE_KEY)) !=
custCount && string.IsNullOrEmpty(searchCriteria))
{
AdvWorksDBCache.Remove(CUSTOMER_CACHE_KEY);
}
}
if (string.IsNullOrEmpty(searchCriteria))
AdvWorksDBCache.Add(CUSTOMERCOUNT_CACHE_KEY , custCount);
}
catch (Exception e)
{
throw;
}
return custCount ;
}
我们在这里使用缓存只是为了减少不必要的数据库调用。因此,添加一个名为“AdvWorksDBCache
”的新类。该类将具有标准的函数,如 Add
、Get
、Remove
用于缓存。它还有一个 GetData
函数,仅用于从缓存数据中返回数据页。请参阅源代码以获得更好的理解。
步骤 3:现在我们将创建 UI。您可以在工具栏中找到 GridView
服务器控件。将其拖放到 default.aspx。暂时将其保持原样。稍后我们将对其进行配置。
现在从工具栏将 ObjectDataSource
拖放到 Default.aspx。我们必须为 ObjectDataSource
设置以下属性:
Id = odsCustomers
SelectMethod = GetCustomersSortedPage
SelectCountMethod = GetCustomersCount
TypeName = DemoGrid.DAL.AdvWorksDB
(完整的 DB 类名)SortParameterName = sortExpression
EnablePaging = true
设置完这些属性后,您的代码将如下所示:
<asp:ObjectDataSource ID="odsCustomers" runat="server"
SelectMethod="GetCustomersSortedPage"
TypeName="DemoGrid.DAL.AdvWorksDB"
EnablePaging="True" SelectCountMethod="GetCustomersCount"
SortParameterName="sortExpression">
</asp:ObjectDataSource>
现在将 DataPager
拖放到 Default.aspx 并根据您的分页格式设置属性。我已将其设置如下:
<asp:DataPager ID="pager" runat="server" PagedControlID="gvCustomers">
<Fields>
<asp:NextPreviousPagerField FirstPageText="<<" LastPageText=">>"
NextPageText=">" PreviousPageText="<"
ShowFirstPageButton="True"
ShowNextPageButton="False" ButtonCssClass="datapager" />
<asp:NumericPagerField ButtonCount="10"
NumericButtonCssClass="datapager"
CurrentPageLabelCssClass="datapager" />
<asp:NextPreviousPagerField LastPageText=">>" NextPageText=">"
ShowLastPageButton="True"
ShowPreviousPageButton="False" ButtonCssClass="datapager" />
</Fields>
</asp:DataPager>
现在是时候配置 gridview
了。我们必须将 DataSourceId
设置为 odsCustomers
,这是我们的 ObjectDataSource
,AutoGenerateColumns = false
,AllowSorting = true
,并设置 OnDataBound
事件。在这里,我们还需要 pagesize
下拉框和 GridView
底部的 label
,以便用户可以更改每页记录数。我已将其配置如下:
<cc1:GridView ID="gvCustomers" runat="server" AutoGenerateColumns="False"
AllowSorting="True"
CssClass="tablestyle" OnDataBound="gvCustomers_DataBound"
DataSourceID="odsCustomers" AllowPaging="True" >
<AlternatingRowStyle CssClass="altrowstyle" />
<HeaderStyle CssClass="headerstyle" />
<RowStyle CssClass="rowstyle" Wrap="false" />
<EmptyDataRowStyle BackColor="#edf5ff" Height="300px"
VerticalAlign="Middle" HorizontalAlign="Center" />
<EmptyDataTemplate >
No Records Found
</EmptyDataTemplate>
<Columns>
<asp:BoundField SortExpression="customerkey"
DataField="customerkey" HeaderText="Customer Key" />
<asp:BoundField SortExpression="City"
DataField="City" HeaderText="City" />
<asp:BoundField DataField="CustomerAlternateKey"
HeaderText="Customer Alternate Key"
SortExpression="CustomerAlternateKey" />
<asp:BoundField DataField="Title" HeaderText="Title"
SortExpression="Title"/>
<asp:BoundField DataField="FirstName"
HeaderText="First Name" SortExpression="FirstName"/>
<asp:BoundField DataField="LastName"
HeaderText="Last Name" SortExpression="LastName"/>
<asp:BoundField DataField="BirthDate"
HeaderText="Birth Date" SortExpression="BirthDate"/>
</Columns>
<PagerTemplate >
<table width="100%" >
<tr>
<td style="text-align: left">
Page Size:
<asp:DropDownList ID="ddPageSize"
runat="server" EnableViewState="true"
OnSelectedIndexChanged=
"ddPageSize_SelectedIndexChanged"
AutoPostBack="true">
<asp:ListItem Text="10" ></asp:ListItem>
<asp:ListItem Text="25" ></asp:ListItem>
<asp:ListItem Text="50" ></asp:ListItem>
</asp:DropDownList>
</td>
<td style="text-align: right">
<asp:Label ID="lblPageCount" runat="server">
</asp:Label>
</td>
</tr>
</table>
</PagerTemplate>
</cc1:GridView>
现在您可以运行了。看看它的性能。您可以将 datapager
和 gridview
放在 AJAX updatepanel
中,以消除闪烁效果。
在第二部分,我们将添加 GridView
的搜索功能。
注释
- 我编写了一个缓存类,只是为了演示缓存能力。您可以根据需要修改缓存类并添加依赖项。您可以利用
ObjectDataSource
的缓存属性。 - 您可以像平常使用
GridView
一样插入checkbox
列。但在这里,当用户选中/取消选中checkbox
并导航到数据时,您必须维护一个已选行列表。 - 您也可以使用 LINQ to SQL。您只需修改生成类中的方法即可在
ObjectDataSource
中使用。
第二部分
我们讨论了如何在不影响性能的情况下在 GridView
中显示大量数据。现在在第二部分,我们将继续使用同一个示例,并在 GridView
上构建搜索功能。

概述
我们将搜索缓存的数据,并将仅 10 条记录(取决于每页记录数)绑定到 GridView
。这样,我们可以减少数据库调用并保持性能。
Using the Code
首先,我们必须在 GridView
上方添加搜索标题。我们将添加一个用于列的 dropdownbox
,一个用于搜索条件的另一个 dropdown
,以及一个用于搜索值的 textbox
。我们还将添加“搜索”和“重置”按钮。我已将此代码添加在 GridView
上方的面板中,如下所示:
<asp:Panel ID="pnlSearch" runat="server" >
<table style="background-color:#C7CFF7; border-width:3px;
border-style:solid; margin: 0px 20px 0px 0px;">
<tr>
<td colspan="5">
<asp:Label ID="lblSearchError" runat="server"
ForeColor="Red" ></asp:Label>
</td>
</tr>
<tr>
<td align="left">Search Column</td>
<td align="left">Search Criteria</td>
<td align="left">Search Value</td>
<td></td>
<td></td>
</tr>
<tr>
<td><asp:HiddenField ID="hfSearchCriteria" runat="server" />
<asp:DropDownList ID="ddSearchField" Width="150px" runat="server">
<asp:ListItem Text="Customer Key"
Value="customerkey"></asp:ListItem>
<asp:ListItem Text="City" Value="City"></asp:ListItem>
<asp:ListItem Text="Customer Alternate Key"
Value="CustomerAlternateKey"></asp:ListItem>
<asp:ListItem Text="Title" Value="Title"></asp:ListItem>
<asp:ListItem Text="First Name" Value="FirstName">
</asp:ListItem>
<asp:ListItem Text="Last Name" Value="LastName">
</asp:ListItem>
<asp:ListItem Text="Birth Date" Value="BirthDate">
</asp:ListItem>
</asp:DropDownList>
</td>
<td>
<asp:DropDownList ID="ddSearchCriteria" runat="server">
<asp:ListItem Text= "Contains" ></asp:ListItem>
<asp:ListItem Text= "DoesNotContain" ></asp:ListItem>
<asp:ListItem Text="EqualTo" ></asp:ListItem>
<asp:ListItem Text= "NotEqualTo" ></asp:ListItem>
<asp:ListItem Text= "GreaterThan"></asp:ListItem>
<asp:ListItem Text= "LessThan" ></asp:ListItem>
<asp:ListItem Text= "GreaterThanOrEqualTo" ></asp:ListItem>
<asp:ListItem Text= "LessThanOrEqualTo"></asp:ListItem>
</asp:DropDownList>
</td>
<td>
<asp:TextBox ID="txtSearchValue" runat="server"></asp:TextBox>
</td>
<td>
<asp:Button ID="btnSearch" CssClass="searchbtn"
runat="server" OnClick="btnSearch_Click" Text="Search" />
</td>
<td>
<asp:Button ID="btnReload" CssClass="reloadbtn"
runat="server" OnClick="btnReload_Click" Text="Reload" />
</td>
</tr>
</table>
</asp:Panel>
如果您注意到,我使用了 1 个隐藏字段“hfSearchCriteria
”,它将包含完整的搜索条件字符串,例如“CustomerKey=11000
”。我们将将其作为 SelectParameters
传递给 ObjectDataSourse
,如下所示:
<asp:ObjectDataSource ID="odsCustomers" runat="server"
SelectMethod="GetCustomersSortedPage" TypeName="DemoGrid.DAL.AdvWorksDB"
EnablePaging="True" SelectCountMethod="GetCustomersCount"
SortParameterName="sortExpression">
<SelectParameters>
<asp:ControlParameter ControlID="hfSearchCriteria"
Name="searchCriteria" Direction="Input" />
</SelectParameters>
</asp:ObjectDataSource>
您可以通过向 ObjectDataSource
的属性窗口添加 SelectParameters
集合来设置此项,如下所示:

每当绑定 GridView
时,ObjectDataSource
都会将隐藏字段的值传递给 select
方法。在我们的例子中,它是“GetCustomerSortedPage
”。实际的搜索发生在缓存类 AdvWorksDBCache
中。如果您查看 AdvWorksDBCache
的 GetData
方法,我们会根据搜索条件过滤 datatable,并根据 startingRowIndex
和 MaximumRecords
返回记录。在搜索按钮单击时,我们只需构建搜索字符串并将其分配给隐藏字段,然后重新绑定 GridView
。请参阅附加的源代码以获得更多理解。这样,我们就可以在 GridView
上实现搜索功能。希望您会喜欢。