0

صفحه بندی بهینه در دیتاگریدی با تعداد رکوردهای بالا

 
amirpetrucci0261
amirpetrucci0261
کاربر طلایی1
تاریخ عضویت : تیر 1388 
تعداد پست ها : 27726
محل سکونت : http://zoomstar.ir/

صفحه بندی بهینه در دیتاگریدی با تعداد رکوردهای بالا

اگرچه ما متیوانیم با استفاده از DataSet به طور خودکار اطلاعات موجود در یک دیتاگرید را صفحه بندی کنیم اما زمانی که تعداد رکوردهای ما زیاد باشد این کار منجر به اشغال حجم زیادی از حافظه و همچنین سرعت و بازدهی پایین خواهد شد.
تکنیکی که در این برنامه قصد داریم به آن بپردازیم این است که بدون استفاده از DataSet بتوانیم این حجم از داده ها را صفحه بندی کنیم. دقت کنید که میخواهیم دیتاگرید ما در نهایت چیزی شبیه به این باشد:

 
برای فعال کردن صفحه بندی میبایست دو ویژگی AllowPaging و AllowCustomPaging برابر true باشند. زمانی که AllowCustomPaging به طور پیش فرض برابر false باشد، دیتاگرید اینگونه در نظر میگیرد که همه داده هایی که قرار است نمایش یابند، در منبع داده ( Data source ) موجود میباشند. ضمن اینکه گروهی از رکوردها را برای نمایش از مکان CurrentPageIndex تا PageSize محاسبه میکند.
زمانی که AllowCustomPaging برابر true باشد، دیتاگرید انتظار تنها یک صفحه از آن داده هایی را دارد که قرار است نمایش دهد و در این حالت برنامه نویس است که مسوول پرکردن منبع داده با داده های مناسب است. به کد دیتاگرید دقت کنید:

<asp:DataGrid ID="dgBooks" runat="server"
BorderColor="#000080"
BorderWidth="2px"
AutoGenerateColumns="False"
Width="90%"
HorizontalAlign="Center"
AllowPaging="True"
AllowCustomPaging="True"
PageSize="10"
PagerStyle-Visible="False">

دقت کنید که در این مثال ما از صفحه بندی خود دیتاگرید استفاده ننموده ایم و خودمان به صورت دستی 4 دکمه بر روی فرم قرار داده ایم که برای پیمایش صفحات استفاده میشوند.

protected void Page_Load(object sender, EventArgs e)
{
if (Page.IsPostBack)
{
currentPage = Convert.ToInt32(labCurrentPage.Text) - 1;
totalPages = Convert.ToInt32(labTotalPages.Text);
}
else
{
// This is the first rendering of the form so set the current page to
// the first page and bind the data
currentPage = 0;
bindData();
}
}

در رخداد Page_Load، در اولین زمانی که صفحه بارگذاری میشود، متغیر currentPage را با صفر مقداردهی کرده ایم و سپس متد bindData را برای جمع آوری داده ها و مقید سازی دیتاگرید به آن استفاده نموده ایم.


اما در زمانی که صفحه مجددا به سرور ارسال یا post back میشود، ابتدا از روی برچسب ها متغیرهای currentPageو totalPages مقداردهی میشوند. سپس بوسیله مدیر رخدادهای مربوطه ( event handler ) داده های مناسب بازیابی شده و دیتاگرید به آنها مقید میشود.


در این کد ما 4 مدیر رخداد برای مدیریت رخدادهایی که در اثر کلیلک کردن دکمه ها رخ میدهند طراحی کرده ایم. این مدیر رخدادها currentPage را با مقدار مناسب مقداردهی کرده و مجددا دیتاگرید را به منبع داده ها مقید سازی میکنند. برای بهبود بازدهی این مدیر رخدادها بررسی میکنند که آیا اصلا صفحه نیازی به تغییر و مقید شدن مجدد دارد یا خیر.


متد bindData در این مثلا از رویه های ذخیره شده یا Stored procedures برای بازیابی اطلاعات مناسب استفاده میکند. این رویه ها این پارامترها را دریافت میکنند: pageNumber، pageSizeو totalRecords


pageNumber

مشخص کننده صفحه ای است که قرار است نمایش یابد


pageSize

یک پارامتر ورودی است که تعداد سطرهایی که قرار است در هر صفحه نمایش یابند را مشخص میکند و میبایست دقیقا با مقدار

PageSize

در دیتاگرید برابر باشد.


totalRecords

یک پارامتر خروجی است که تعداد رکوردهای در دسترس برای نمایش دادن را برمیگرداند.


رویه ذخیره شده ابتدا اندیس اولین رکورد و آخرین رکورد را بریا نمایش به این شکل محاسبه میکند:

SELECT @firstRecordInPage = @pageNumber * @pageSize + 1
SELECT @lastRecordInPage = @firstRecordInPage + @pageSize

سپس یک جدول موقتی بر اساس جدول Book ایجاد میشود که حاوی یک ستون ID که شماره آن به صورت خودکار افزایش میابد برای شماره گذاری رکوردها از 1 تا تعداد نهایی رکوردها میباشد. این کار موجب میشود تنها رکوردهایی که نیازداریم را انتخاب کنیم:

CREATE TABLE #Book
(
[ID] [int] IDENTITY (1, 1) NOT NULL ,
[BookID] [int] NOT NULL ,
[Title] [nvarchar] (100) NOT NULL ,
[ISBN] [nvarchar] (50) NOT NULL ,
[Publisher] [nvarchar] (50) NOT NULL
)

سپس داده ها از جدول Book به حدول موقت کپی شده و بر حسب عنوان کتاب مرتب میشوند.

INSERT INTO #Book
(BookID, Title, ISBN, Publisher)
SELECT BookID, Title, ISBN, Publisher FROM Book ORDER BY Title

قدم بعدی این است که یا ارسال یک کوئری به حدول موقت، تنها آن سطرهایی را بازیابی کنیم که به آنها نیاز داریم.

SELECT * FROM #Book
WHERE ID >= @firstRecordInPage
AND ID < @lastRecordInPage

سپس میبایست تعداد رکوردهای موجود در جدول Book را بدست آورده و totalRecords را با مقدار مذکور مقداردهی کنیم.

SELECT @totalRecords = COUNT(*) FROM Book

کد رویه ذخیره شده به این شرح است

CREATE PROCEDURE getPageData
@pageNumber INT,
@pageSize INT,
@totalRecords INT OUTPUT
AS
DECLARE @firstRecordInPage INT
DECLARE @lastRecordInPage INT
-- Calculate the number of rows needed to get to the current page
SELECT @firstRecordInPage = @pageNumber * @pageSize + 1
SELECT @lastRecordInPage = @firstRecordInPage + @pageSize
-- Create a temporary table to copy the book data into.
-- Include only the columns needed with an additional ID
-- column that is the primary key of the temporary table.
-- In addition, it is an identity that will number the
-- records copied into the table starting with 1 thus allowing
-- us to query only for the specific records needed for the
-- requested page.
CREATE TABLE #Book
(
[ID] [int] IDENTITY (1, 1) NOT NULL ,
[BookID] [int] NOT NULL ,
[Title] [nvarchar] (100) NOT NULL ,
[ISBN] [nvarchar] (50) NOT NULL ,
[Publisher] [nvarchar] (50) NOT NULL
)
-- Copy the data from the book table into the temp table
INSERT INTO #Book
(BookID, Title, ISBN, Publisher)
SELECT BookID, Title, ISBN, Publisher FROM Book ORDER BY Title
-- Get the rows required for the passed page
SELECT * FROM #Book
WHERE ID >= @firstRecordInPage
AND ID < @lastRecordInPage
-- Get the total number of records in the table
SELECT @totalRecords = COUNT(*) FROM Book
GO

همچنین کد صفحه aspx ما چنین خواهد بود:

<%@ Page Language="VB" MasterPageFile="~/ASPNetCookbookVB.master"
AutoEventWireup="false"
CodeFile="CH02 LargeDatasetPagingVB1.aspx.vb"
Inherits="ASPNetCookbook.VBExamples.CH02LargeDatasetPagingVB1"
Title="DataGrid With Large Data Set Paging" %>
<asp:Content ID="pageBody" runat="server" ContentPlaceHolderID="PageBody">
<div align="center" class="pageHeading">
DataGrid With Large Data Set Paging (VB)
</div>
<asp:DataGrid ID="dgBooks" runat="server"
BorderColor="#000080"
BorderWidth="2px"
AutoGenerateColumns="False"
Width="90%"
HorizontalAlign="Center"
AllowPaging="True"
AllowCustomPaging="True"
PageSize="10"
PagerStyle-Visible="False">
<HeaderStyle HorizontalAlign="Center" CssClass="tableHeader" />
<ItemStyle CssClass="tableCellNormal" />
<AlternatingItemStyle CssClass="tableCellAlternating" />
<Columns>
<asp:BoundColumn HeaderText="Title" DataField="Title"/>
<asp:BoundColumn HeaderText="ISBN" DataField="ISBN"
ItemStyle-HorizontalAlign="Center"/>
<asp:BoundColumn HeaderText="Publisher" DataField="Publisher"
ItemStyle-HorizontalAlign="Center"/>
</Columns>
</asp:DataGrid>
<table width="40%" border="0" align="center">
<tr>
<td colspan="4" align="center">
Displaying page
<asp:Literal id="labCurrentPage" runat="server" /> of
<asp:Literal id="labTotalPages" runat="server" /></td>
</tr>
<tr>
<td align="center">
<input id="btnFirst" runat="server"
type="button"
value="First"
onserverclick="btnFirst_ServerClick"/>
</td>
<td align="center">
<input id="btnPrev" runat="server"
type="button"
value="Prev"
onserverclick="btnPrev_ServerClick"/>
</td>
<td align="center">
<input id="btnNext" runat="server"
type="button"
value="Next"
onserverclick="btnNext_ServerClick"/>
</td>
<td align="center">
<input id="Last" runat="server"
type="button"
value="Last"
onserverclick="btnLast_ServerClick"/>
</td>
</tr>
</table>
</asp:Content>

کد پشت صفحه این مثال نیز چنین است:

using System;
using System.Configuration;
using System.Data;
using System.Data.OleDb;
using System.Web.UI.WebControls;
namespace ASPNetCookbook.CSExamples
{
///***********************************************************************
/// <summary>
/// This class provides the code behind for
/// CH02LargeDatasetPagingCS1.aspx
/// </summary>
public partial class CH02 LargeDatasetPagingCS1 : System.Web.UI.Page
{
// private variables used to store the current page and total number of
// pages. This is required since the CurrentPageIndex and PageCount
// properties of the datagrid cannot be used with custom paging
private int currentPage;
private int totalPages;
///***********************************************************************
/// <summary>
/// This routine provides the event handler for the page load event.
/// It is responsible for initializing the controls on the page.
/// </summary>
///
/// <param name="sender">Set to the sender of the event</param>
/// <param name="e">Set to the event arguments</param>
protected void Page_Load(object sender, EventArgs e)
{
if (Page.IsPostBack)
{
// This is a post back so initialize the current and total page
// variables with the values currently being displayed
currentPage = Convert.ToInt32(labCurrentPage.Text) - 1;
totalPages = Convert.ToInt32(labTotalPages.Text);
}
else
{
// This is the first rendering of the form so set the current page to
// the first page and bind the data
currentPage = 0;
bindData();
}
} // Page_Load
///***********************************************************************
/// <summary>
/// This routine provides the event handler for the first button click
/// event. It is responsible for setting the page index to the first
/// page and rebinding the data.
/// </summary>
///
/// <param name="sender">Set to the sender of the event</param>
/// <param name="e">Set to the event arguments</param>
protected void btnFirst_ServerClick(Object sender,
System.EventArgs e)
{
// set new page index and rebind the data
if (currentPage > 0)
{
currentPage = 0;
bindData();
}
} // btnFirst_ServerClick
///***********************************************************************
/// <summary>
/// This routine provides the event handler for the previous button click
/// event. It is responsible for setting the page index to the previous
/// page and rebinding the data.
/// </summary>
///
/// <param name="sender">Set to the sender of the event</param>
/// <param name="e">Set to the event arguments</param>
protected void btnPrev_ServerClick(Object sender,
System.EventArgs e)
{
// set new page index and rebind the data
if (currentPage > 0)
{
currentPage -= 1;
bindData();
}
} // btnPrev_ServerClick
///******************************************************************
/// <summary>
/// This routine provides the event handler for the next button click
/// event. It is responsible for setting the page index to the next
/// page and rebinding the data.
/// </summary>
///
/// <param name="sender">Set to the sender of the event</param>
/// <param name="e">Set to the event arguments</param>
protected void btnNext_ServerClick(Object sender,
System.EventArgs e)
{
// set new page index and rebind the data
if (currentPage < totalPages - 1)
{
currentPage += 1;
bindData();
}
} // btnNext_ServerClick
///***********************************************************************
/// <summary>
/// This routine provides the event handler for the last button click
/// event. It is responsible for setting the page index to the last
/// page and rebinding the data.
/// </summary>
///
/// <param name="sender">Set to the sender of the event</param>
/// <param name="e">Set to the event arguments</param>
protected void btnLast_ServerClick(Object sender,
System.EventArgs e)
{
// set new page index and rebind the data
if (currentPage < totalPages - 1)
{
currentPage = totalPages - 1;
bindData();
}
} // btnLast_ServerClick
///******************************************************************
/// <summary>
/// This routine queries the database for the data to displayed and binds
/// it to the datagrid
/// </summary>
private void bindData()
{
OleDbConnection dbConn = null;
OleDbCommand dCmd = null;
OleDbDataReader dReader = null;
OleDbParameter param = null;
String strConnection = null;
String strSQL = null;
int totalRecords = 0;
try
{
// get the connection string from web.config and open a connection
// to the database
strConnection = ConfigurationManager.
ConnectionStrings["dbConnectionString"].ConnectionString;
dbConn = new OleDbConnection(strConnection);
dbConn.Open();
// create command to execute the stored procedure along with the
// parameters required in/out of the procedure
strSQL = "getPageData"; // name of stored procedure
dCmd = new OleDbCommand(strSQL, dbConn);
dCmd.CommandType = CommandType.StoredProcedure;
param = dCmd.Parameters.Add("pageNumber", OleDbType.Integer);
param.Direction = ParameterDirection.Input;
param.Value = currentPage;
param = dCmd.Parameters.Add("pageSize", OleDbType.Integer);
param.Direction = ParameterDirection.Input;
param.Value = dgBooks.PageSize;
param = dCmd.Parameters.Add("totalRecords", OleDbType.Integer);
param.Direction = ParameterDirection.Output;
//execute the stored procedure and set the datasource for the datagrid
dReader = dCmd.ExecuteReader();
dgBooks.DataSource = dReader;
dgBooks.DataBind();
// close the dataReader to make the output parameter available
dReader.Close();
// output information about the current page and total number of pages
totalRecords = Convert.ToInt32(dCmd.Parameters["totalRecords"].Value);
totalPages = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(totalRecords) /
dgBooks.PageSize));
labTotalPages.Text = totalPages.ToString();
labCurrentPage.Text = (currentPage + 1).ToString();
} // try
finally
{
//clean up
if (dReader != null)
{
dReader.Close();
}
if (dbConn != null)
{
dbConn.Close();
}
} // finally
} // bindData
} // CH02LargeDatasetPagingCS1
}

چهارشنبه 10 آذر 1389  5:17 AM
تشکرات از این پست
دسترسی سریع به انجمن ها