گرفتن اطلاعات از دیتابیس بصورت مرحله ای (Paging یا صفحه بندی کردن اطلاعات) - هفت خط کد انجمن پرسش و پاسخ برنامه نویسی

گرفتن اطلاعات از دیتابیس بصورت مرحله ای (Paging یا صفحه بندی کردن اطلاعات)

+2 امتیاز
سلام دوستان خسته نباشین :)

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

میخواستم بپرسم ما چطور میتونیم از دیتابیس اطلاعات رو تیکه تیکه اما بترتیب بگیریم ؟

مثلا فرض کنید ما 30 تا row  تو یه table داریم ... حالا من میخوام اطلاعات رو 5 تا 5 تا بگیرم یعنی دفعه اول از 1 تا 5... دفعه دوم از 5 تا 10 و این همینطور ادامه پیدا کنه...

فرض کنید ما یه button داریم و هر بار روش کلیک کردیم این اتفاق بیوفته...

حالا کوئری که مینویسیم باید چه شکلی باشه ؟
سوال شده اسفند 26, 1392  بوسیله ی amc (امتیاز 280)   3 5 16
دوباره تگ گذاری شد اسفند 26, 1392 بوسیله ی veniz2008

1 پاسخ

+4 امتیاز
 
بهترین پاسخ

سلام.

چیزی که شما دنبالش میگردید، در سی شارپ اصطلاحا بهش Paging (صفحه بندی کردن) گفته میشه. مثلا زمانیکه تعداد رکوردهای جدولمون زیاد هست هم بخاطر اینکه سرعت Load کردن اطلاعات زیاد بشه و هم اینکه واقعا تعداد رکوردهای زیاد در یک لحظه به درد کاربر نمی خوره، از این paging استفاده می کنن که البته بسیار پر کاربرد هم هست.

من مراحل کار رو به همراه کدهای مورد نظر قدم به قدم توضیح میدم تا کامل متوجه موضوع بشید.

اصول کار اینه که شما یه عدد بعنوان تعداد رکوردهای هر صفحه باید مشخص کنید. مثلا هر صفحه (هر نمایش گرید) شامل 10 رکورد باشه.

برای بار اول (page = 1) بایستی 10 رکورد اول (رکوردهای 1 تا 10) ، برای بار دوم (page = 2) بایستی 10 رکورد دوم (رکوردهای 11 تا 20) و ...

پس نیاز داریم که علاوه بر مشخص شدن تعداد رکوردهای هر نمایش، بدونیم هر بار که درخواست میدیم، چندین نمایش (چندمین page) رو درخواست دادیم.

مطلب بعدی در زمان انتخاب رکوردهای هر page اینه که باید محدوده این رکوردها مشخص باشه که از چه شماره ای تا چه شماره ای رو برگردونه. مثلا برای page = 2 باید از رکودهای 11 تا 20 رو برامون برگردونه.

حالا می خوام این توضیحات رو در قالب کد sql مورد نظر بیارم. در ادامه من از یک stored procedure برای این کار استفاده میکنم.

برای این کار در سمت sql، ابتدا یک جدول موقت ایجاد می کنم که فیلدهای این جدول دقیقا مثل فیلدهای جدول اصلیتون هست و تمام رکوردهای جدول مورد نظرم رو داخل این جدول موقت می ریزم و یک فیلد ID هم خودم به این جدول بصورت Identity اضافه می کنم. این فیلد بخاطر این هست که می خوام رکوردهای جدول، شماره پشت سر هم داشته باشند. اکیدا" توصیه می کنم حتی اگر جدولتون فیلد Identity داره باز هم این فیلدی رو که در sp پایین هست بهش دست نزنید. چون ممکنه با اینکه جدول شما فیلد identity داشته باشه ولی ازش رکوردهایی رو حذف کرده باشید و ترتیب شماره های فیلد identity بهم خورده باشه.

در کد زیر همونطور که در بالا هم اشاره کردم، نیاز دارید که تعداد رکوردهای درخواستی و شماره page درخواستی و همچنین محدوده رکوردهایی که باید واکشی بشن رو داشته باشیم(متغیرهای FirstRecord@ و LastRecord@ دقیقا برای همین منظور تعریف شدن).

نحوه محاسبه FirstRecord@ و LastRecord@ هم با یک عدد گذاری ساده می تونید کاملا متوجهش بشید.

با این توضیحات کد stored procedure زیر رو ملاحظه بفرمایید :

Create PROCEDURE [dbo].[sp_PagedItem]
(
     @Page int,
  
     @RecordsPerPage int
 )
AS
 CREATE
TABLE #TempItems
 
(
    ID int IDENTITY,Order_Id int ,OrderNumber int,Person_Id int
)
INSERT
INTO #TempItems(O_Id,OrderNo,P_Id)
 
SELECT * FROM Orders
 
DECLARE
@FirstRecord int, @LastRecord int
 
SELECT
@FirstRecord =(@Page - 1)* @RecordsPerPage
 
SELECT
@LastRecord =((@Page * @RecordsPerPage) + 1)
 
SELECT
*
FROM
#TempItems
 
WHERE
ID > @FirstRecord AND ID < @LastRecord

حالا در سمت برنامه، یک گرید داشته باشید و دو دکمه Next و Previous برای نمایش رکوردهای بعدی و قبلی.

زمانی می تونید رکوردهای بعدی رو نمایش بدید که واقعا رکوردی باقی مونده باشه (تعداد page های کل جدول شما بزرگتر از page جاری شما باشه. مثلا کل جدول شما 5 صفحه هست و شما الان در صفحه 4 هستید) و همچنین زمانی می تونید رکوردهای قبلی رو نمایش بدید که page جاری شما بزرگتر از 1 باشه (مثلا در page = 2 هستید و می خواید page قبلی یعنی page = 1 رو نمایش بدید).

در لحظه Load با استفاده از همین sp تعداد رکورد مد نظرتون (مثلا 10 رکورد برای هر بار نمایش) رو واکشی کنید و درون گرید نمایش بدید.همونطور که در بالا هم توضیح دادم شما در هر بار فراخوانی sp باید شماره page جاری (بار اول در رویداد load میشه page = 1) و تعداد رکوردهای مد نظرتون رو برای sp بفرستید.

برای شماره page جاری یه متغیر سراسری از نوع int تعریف کنید مثلا CurrentPage و در رویداد Load بعد از واکشی رکوردها و نمایش اونها در گرید، مقدارش رو 1 قرار بدید. از این به بعد هر وقت روی دکمه بعدی کلیک می کنید باید در انتهای کدهای دکمه (تاکید میکنم در انتهای کدهای دکمه) به این متغیر CurrentPage یک واحد اضافه کنید و هر بار روی دکمه قبلی کلیک می کنید باید در انتهای کدهای دکمه (تاکید میکنم در انتهای کدهای دکمه) از این متغیر CurrentPage یک واحد کم کنید.

تمام این صحبت ها در کدهای زیر به روشنی قابل دیدن هستن (در سازنده فرم که قبل از رویداد Load اجرا میشه، تعداد کل صفحات جدول محاسبه شده که در شرط if از این مقدار استفاده کردیم) :

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;

namespace test
{
    public partial class frmpaging : Form
    {
        SqlConnection con = new SqlConnection("Server = .\\md2012;DataBase = testsql;Integrated Security = true");
        int TotalPages;
        int currentpage = 0;
        public frmpaging()
        {
            InitializeComponent();
            // بدست آوردن تعداد کل صفحات موجود در جدول در سازنده. تابع سازنده قبل از رویداد لود اجرا میشه
            SqlDataAdapter da = new SqlDataAdapter("select count(*) from orders", con);
            DataTable dt = new DataTable();
            da.Fill(dt);
            TotalPages = Convert.ToInt32(dt.Rows[0][0].ToString()) / 10;
        }
        //
        private void BtnNext_Click(object sender, EventArgs e)
        {
            // اگر صفحه جاری کوچکتر از تعداد کل صفحات باشه، صفحه بعدی وجود خواهد داشت
            if(currentpage < TotalPages)
            {
                SqlDataAdapter da = new SqlDataAdapter("sp_pagedItem", con);
                da.SelectCommand.CommandType = CommandType.StoredProcedure;
                da.SelectCommand.Parameters.AddWithValue("@page", currentpage + 1);
                da.SelectCommand.Parameters.AddWithValue("@RecordsPerPage", 10);
                DataTable dt = new DataTable();
                da.Fill(dt);
                dataGridView1.DataSource = dt;
                currentpage++;
            }
            
        }
        //
        private void BtnPrevious_Click(object sender, EventArgs e)
        {
            // اگر صفحه جاری بزرگتر از 1 باشه، صفحه قبلی وجود خواهد داشت
            if (currentpage > 1)
            {
                SqlDataAdapter da = new SqlDataAdapter("sp_pagedItem", con);
                da.SelectCommand.CommandType = CommandType.StoredProcedure;
                da.SelectCommand.Parameters.AddWithValue("@page", currentpage - 1);
                da.SelectCommand.Parameters.AddWithValue("@RecordsPerPage", 10);
                DataTable dt = new DataTable();
                da.Fill(dt);
                dataGridView1.DataSource = dt;
                currentpage--;
            }
        }
        //
        private void frmpaging_Load(object sender, EventArgs e)
        {
            // اولین بار در اجرای فرم برنامه، رکوردهای مورد نظر رو از جدول واکشی میکنه و به کاربر نمایش میده
            SqlDataAdapter da = new SqlDataAdapter("sp_pagedItem", con);
            da.SelectCommand.CommandType = CommandType.StoredProcedure;
            da.SelectCommand.Parameters.AddWithValue("@page", 1);
            da.SelectCommand.Parameters.AddWithValue("@RecordsPerPage", 10);
            DataTable dt = new DataTable();
            da.Fill(dt);
            dataGridView1.DataSource = dt;
            currentpage = 1;
        }
    }
}

موفق باشید.

پاسخ داده شده اسفند 26, 1392 بوسیله ی veniz2008 (امتیاز 2,083)   1 5 21
انتخاب شد اسفند 26, 1392 بوسیله ی amc
سلام
حقیقتش انتظار همچین توضیح کاملی رو نداشتم واقعا دستتون درد نکنه :)
من قراره تو c++ این رو پیداسازی کنم اما با توضیحات کاملی که دادین متوجه قضیه شدم.
از اینکه وقت عزیزتونو صرف من کردین ممنونم :)
موفق و پیروز باشین
تشکر.
(تازه این سایت رو دیدم، قصد عوضیت نداشتم اما جواب این سوال مجبورم کرد که ثبت نام کنم)
با اینکه کلیات جواب درسته اما استفاده از روش Identity کاملا روش ناصحیحی هست. به این علت که idenity ها الزاما به ترتیب نیستن و به هر دلیلی اگه رکورد درج نشه، یک گپ میافته بین شون، در نتیجه به تعداد گپ ها، رکورد کمتری در صفحه دیده میشه. روش درسته استفاده از rownumber هست، که الان در حوصلم نیست توضیح بدم. یک جستجو بکنید جواب رو پیدا می کنید.
توی گوگل بزنید rownumber sql server یا هر دیتابیس دیگه ای
...