Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
által Scott Mitchell
Az adatbemutatás-vezérlő alapértelmezett lapozási lehetősége nem megfelelő nagy mennyiségű adat használatakor, mivel az alapul szolgáló adatforrás-vezérlő minden rekordot lekér, annak ellenére, hogy csak az adatok egy részhalmaza jelenik meg. Ilyen körülmények között testreszabott lapozáshoz kell fordulnunk.
Bevezetés
Ahogy az előző oktatóanyagban is tárgyaltuk, a lapozás kétféleképpen valósítható meg:
- Az alapértelmezett lapozás az adat-webvezérlő intelligens címkéjében található Lapozás engedélyezése lehetőség bejelölésével valósítható meg; azonban amikor megtekint egy adatoldalt, az ObjectDataSource lekéri az összes rekordot, annak ellenére, hogy csak egy részhalmaz jelenik meg az oldalon
- Az egyéni lapozás javítja az alapértelmezett lapozás teljesítményét, ha csak azokat a rekordokat kéri le az adatbázisból, amelyeket meg kell jeleníteni a felhasználó által kért adatok adott lapján; az egyéni lapozás azonban egy kicsit több erőfeszítést igényel az alapértelmezett lapozásnál
A könnyű megvalósítás miatt csak jelölje be a jelölőnégyzetet, és kész! az alapértelmezett lapozás vonzó lehetőség. Naiv megközelítése az összes rekord beolvasása során ugyanakkor nem valószerű választás, ha elegendően nagy mennyiségű adatot kell feldolgozni vagy ha sok egyidejű felhasználó van a webhelyen. Ilyen körülmények között az egyéni lapozáshoz kell fordulnunk, hogy rugalmas rendszert biztosíthassunk.
Az egyéni lapozás kihívása egy olyan lekérdezés írása, amely egy adott adatoldalhoz szükséges rekordok pontos készletét adja vissza. Szerencsére a Microsoft SQL Server 2005 új kulcsszót biztosít a rangsorolási eredményekhez, így olyan lekérdezést írhatunk, amely hatékonyan lekéri a rekordok megfelelő részhalmazát. Ebben az oktatóanyagban bemutatjuk, hogyan használhatja ezt az új SQL Server 2005-kulcsszót egyéni lapozás megvalósítására a GridView-vezérlőkben. Míg az egyéni lapozás felhasználói felülete megegyezik az alapértelmezett lapozási felületével, az egyéni lapozással az egyik oldalról a másikra lépve több nagyságrenddel gyorsabb lehet, mint az alapértelmezett lapozás.
Megjegyzés:
Az egyéni lapozás által mutatott pontos teljesítménynövekedés a lapozandó rekordok teljes számától és az adatbázis-kiszolgálóra helyezett terheléstől függ. Az oktatóanyag végén áttekintünk néhány durva metrikát, amelyek bemutatják az egyéni lapozással elért teljesítmény előnyeit.
1. lépés: Az egyéni lapozási folyamat megértése
Az adatok lapozásakor az adott lapon megjelenő pontos rekordok a kért adatok oldalától és az oldalonként megjelenített rekordok számától függenek. Tegyük fel például, hogy a 81 terméket szeretnénk lapra tenni, és 10 terméket jelenítünk meg oldalanként. Az első oldal megtekintésekor az 1–10. termékeket szeretnénk használni; a második oldal megtekintésekor a 11–20. termék érdekelne minket, és így tovább.
Három változó határozza meg, hogy milyen rekordokat kell lekérni, és hogyan kell megjeleníteni a lapozófelületet:
- Az első sor indexe a megjelenítendő adatoldal első sorának indexe; ez az index úgy számítható ki, hogy az oldalindexet megszorozzuk a laponként megjelenítendő rekordok számával, majd hozzáadunk egyet. Ha például egyszerre 10 rekordot lapoz át, az első oldalon (amelynek lapindexe 0), a Kezdő sor indexe 0 * 10 + 1 vagy 1; a második oldal (amelynek lapindexe 1), a kezdő sor indexe 1 * 10 + 1 vagy 11.
- Maximum sorok az oldalanként megjelenítendő rekordok maximális száma. Ezt a változót maximális sornak nevezzük, mivel az utolsó oldalon kevesebb rekordot ad vissza, mint az oldalméret. Ha például a 81 termék lapszámozása 10 rekordot eredményez oldalanként, a kilencedik és az utolsó oldal csak egy rekorddal fog rendelkezni. Egyetlen oldal sem fog több rekordot megjeleníteni, mint a Maximális sorok érték.
- Összes rekord száma a lapozás alatt álló rekordok teljes száma. Bár ez a változó nem szükséges annak meghatározásához, hogy egy adott oldalhoz milyen rekordokat szeretne lekérni, ez diktálja a lapozófelületet. Ha például 81 terméket lapoznak át, a lapozófelület tudja, hogy kilenc oldalszámot jelenít meg a lapozófelületen.
Az alapértelmezett lapozás esetén a kezdősor-index az oldalindex és az oldalméret plusz egy szorzataként lesz kiszámítva, míg a Maximális sorok egyszerűen az oldalméret. Mivel az alapértelmezett lapozás minden adatoldal megjelenítésekor lekéri az összes rekordot az adatbázisból, az egyes sorok indexe ismert, így a Sorindex indítása sorra való áttérés egyszerű feladat. Ezenkívül a Teljes rekordszám is könnyen elérhető, mivel egyszerűen a DataTable rekordjainak száma (vagy bármilyen objektum az adatbázis eredményeinek tárolására szolgál).
A Kezdő sor indexe és a Sorok maximális száma változók miatt az egyéni lapozási implementációnak csak a kezdősor-indextől kezdődő rekordok pontos részhalmazát, majd az azt követő rekordok maximális sorainak számát kell visszaadnia. A testreszabott lapozás két kihívást jelent:
- Hatékonyan kell társítanunk egy sorindexet a lapozás alatt álló adatok minden sorához, hogy megkezdhessük a rekordok visszaadását a megadott kezdősor-indexben
- Meg kell adnunk a lapozás alatt álló rekordok teljes számát
A következő két lépésben megvizsgáljuk a két kihívás megválaszolásához szükséges SQL-szkriptet. Az SQL-szkript mellett metódusokat is implementálni kell a DAL-ban és a BLL-ben.
2. lépés: A lapozás alatt álló rekordok teljes számának visszaadása
Mielőtt megvizsgálnánk, hogyan kérhető le a megjelenített lap rekordjainak pontos részhalmaza, először nézzük meg, hogyan lehet visszaadni a lapozás alatt álló rekordok teljes számát. Ezekre az információkra a lapozó felhasználói felület megfelelő konfigurálásához van szükség. Az adott SQL-lekérdezés által visszaadott rekordok teljes száma az COUNT összesítő függvény használatával kérhető le. A tábla rekordjainak Products teljes számának meghatározásához például a következő lekérdezést használhatjuk:
SELECT COUNT(*)
FROM Products
Adjunk hozzá egy metódust a DAL-hoz, amely visszaadja ezeket az információkat. Létrehozunk egy DAL metódust, amely TotalNumberOfProducts() végrehajtja a SELECT fenti utasítást.
Először nyissa meg a Northwind.xsd Typed DataSet fájlt a App_Code/DAL mappában. Ezután kattintson a jobb gombbal a ProductsTableAdapter Tervezőben, és válassza a Lekérdezés hozzáadása parancsot. Ahogy a korábbi oktatóanyagokban láttuk, ez lehetővé teszi egy új metódus hozzáadását a DAL-hoz, amely meghíváskor végrehajt egy adott SQL-utasítást vagy tárolt eljárást. A TableAdapter-metódusokhoz hasonlóan a korábbi oktatóanyagokban is egy alkalmi SQL-utasítást használunk.
1. ábra: Alkalmi SQL-utasítás használata
A következő képernyőn megadhatja, hogy milyen típusú lekérdezést szeretne létrehozni. Mivel ez a lekérdezés egyetlen, skaláris értéket ad vissza, ami a Products táblázat teljes rekordszámát jelenti, válassza azt az SELECT lehetőséget, amelyik egyetlen értéket ad vissza.
2. ábra: A lekérdezés konfigurálása select utasítás használatára, amely egyetlen értéket ad vissza
A használni kívánt lekérdezés típusának megadása után meg kell adnia a lekérdezést.
3. ábra: A SELECT COUNT(*) FROM Products lekérdezés használata
Végül adja meg a metódus nevét. Mint fentebb említettük, használjuk TotalNumberOfProducts.
4. ábra: A DAL metódus neve TotalNumberOfProducts
A Befejezés gombra kattintás után a varázsló hozzáadja a TotalNumberOfProducts metódust a DAL-hoz. A DAL skaláris visszatérési metódusai null értékű típusokat adnak vissza, ha az SQL-lekérdezés eredménye .NULL A COUNT lekérdezésünk azonban mindig nem-NULL értéket ad vissza; ennek ellenére a DAL metódus tetszőleges egész számot ad vissza, amely lehet null értékű is.
A DAL metóduson kívül a BLL-ben is szükség van egy metódusra. Nyissa meg az ProductsBLL osztályfájlt, és adjon hozzá egy TotalNumberOfProducts metódust, amely egyszerűen meghívja a DAL TotalNumberOfProducts metódusát.
Public Function TotalNumberOfProducts() As Integer
Return Adapter.TotalNumberOfProducts().GetValueOrDefault()
End Function
A DAL s TotalNumberOfProducts metódus null értékű egész számot ad vissza, de az s ProductsBLL osztály metódust úgy hoztuk létreTotalNumberOfProducts, hogy egy standard egész számot adjon vissza. Ezért az s ProductsBLL osztály metódusnak a TotalNumberOfProducts DAL metódus TotalNumberOfProducts által visszaadott null értékű egész szám értékrészét kell visszaadnia. A hívás GetValueOrDefault() a null értékű egész szám értékét adja vissza, ha létezik; ha a null értékű egész szám nullazonban az alapértelmezett egész szám, 0.
3. lépés: A rekordok pontos részhalmazának visszaadása
A következő feladatunk olyan metódusok létrehozása a DAL-ban és a BLL-ben, amelyek elfogadják a korábban tárgyalt Kezdő sorindex és Sorok maximális száma változót, és visszaadják a megfelelő rekordokat. Mielőtt ezt tennénk, először nézzük meg a szükséges SQL-szkriptet. Az előttünk álló kihívás az, hogy hatékonyan kell hozzárendelnünk egy indexet a lapozás alatt álló teljes eredmények minden sorához, hogy csak azokat a rekordokat tudjuk visszaadni, amelyek a kezdősor-indexnél kezdődnek (és akár a rekordok maximális rekordszámához is).
Ez nem jelent kihívást, ha már van egy oszlop az adatbázistáblában, amely sorindexként szolgál. Első pillantásra azt gondolhatnánk, hogy a Products tábla ProductID mezője elegendő lenne, mivel az első termék ProductID 1, a második 2, és így tovább. A termék törlése azonban hézagot hagy a sorrendben, és érvényteleníti ezt a megközelítést.
A sorindexet két általános módszer használatával lehet hatékonyan társítani a lapozáshoz használt adatokkal, ezáltal lehetővé téve a rekordok pontos részhalmazának lekérését:
Az SQL Server 2005 s
ROW_NUMBER()kulcsszó használata Újdonság az SQL Server 2005-hez, aROW_NUMBER()kulcsszó rangsorolást társít minden visszaadott rekordhoz bizonyos sorrend alapján. Ez a rangsor minden sor sorindexeként használható.Táblaváltozó és
SET ROWCOUNTAz SQL Server utasításávalSET ROWCOUNTmegadhatja, hogy hány rekordot kell feldolgoznia a lekérdezésnek a befejezés előtt; A táblaváltozók olyan helyi T-SQL-változók, amelyek táblázatos adatokat tárolhatnak, az ideiglenes táblákhoz hasonlóak. Ez a megközelítés egyformán jól működik a Microsoft SQL Server 2005 és az SQL Server 2000 rendszerrel is (míg a megközelítés csak azROW_NUMBER()SQL Server 2005-höz használható).Itt egy olyan táblaváltozót kell létrehozni, amelynek van egy
IDENTITYoszlopa és a táblának olyan oszlopai, amelyek az elsődleges kulcsait tartalmazzák, és amelyeken az adatok lapozása történik. Ezután, az adatokon keresztüli lapozás során, a táblázat tartalma betöltésre kerül a táblaváltozóba, így a tábla egyes rekordjaihoz szekvenciális sorindexet társít azIDENTITYoszlopon keresztül. A táblaváltozó feltöltéseSELECTután a táblaváltozó egy, az alapul szolgáló táblához csatlakoztatott utasítása végrehajtható az adott rekordok lekéréséhez. AzSET ROWCOUNTutasítás intelligensen korlátozza a táblaváltozóba dobandó rekordok számát.Ez a megközelítés hatékonysága a kért oldalszámon alapul, mivel az
SET ROWCOUNTérték a Kezdő sor indexe és a Maximális sorok értékéhez van rendelve. Az alacsony számú oldalak, például az első néhány oldalnyi adat lapszámozása esetén ez a módszer nagyon hatékony. Azonban, amikor egy oldal a végéhez közel van beolvasva, alapértelmezetten lapozásra jellemző teljesítményt mutat.
Ez az oktatóanyag egyéni lapozást implementál a ROW_NUMBER() kulcsszó használatával. A táblaváltozó és SET ROWCOUNT a technika használatával kapcsolatos további információkért lásd: A Hatékonyabb módszer a nagy eredményhalmazokon keresztüli lapozáshoz.
Az ROW_NUMBER() adott sorrendben visszaadott összes rekordhoz tartozó rangsorolás kulcsszója az alábbi szintaxist használja:
SELECT columnList,
ROW_NUMBER() OVER(orderByClause)
FROM TableName
ROW_NUMBER() egy numerikus értéket ad vissza, amely meghatározza az egyes rekordok rangját a megadott sorrend tekintetében. Ha például az egyes termékek rangsorát szeretné megtekinteni, a legdrágábbtól a legkisebbig rendezve, a következő lekérdezést használhatjuk:
SELECT ProductName, UnitPrice,
ROW_NUMBER() OVER(ORDER BY UnitPrice DESC) AS PriceRank
FROM Products
Az 5. ábrán ez a lekérdezés eredménye látható, amikor a Visual Studióban futtatja a lekérdezési ablakot. Vegye figyelembe, hogy a termékek megrendelése ár szerint, valamint az egyes sorok ársorrendje alapján van megadva.
5. ábra: Az árlista minden visszaadott rekordhoz tartozik
Megjegyzés:
ROW_NUMBER() az SQL Server 2005-ben elérhető számos új rangsorolási függvény egyike. A többi rangsorolási funkcióval együtt részletesebben ROW_NUMBER ROW_NUMBER()dokumentációt is elolvashatja.
Ha a záradékban (ORDER BYOVERa fenti példában) megadott UnitPrice oszlop szerint rangsorozza az eredményeket, az SQL Servernek rendeznie kell az eredményeket. Ez egy gyors művelet, ha az oszlop(ok)hoz tartozik egy fürtözött index az eredmények rendezéséhez, vagy van egy fedőindex, egyébként drágább lehet. A megfelelő méretű lekérdezések teljesítményének javítása érdekében érdemes lehet hozzáadni egy nem fürtözött indexet ahhoz az oszlophoz, amellyel az eredményeket rendezi. A teljesítmény szempontjait részletesebben az SQL Server 2005 rangsorolási függvényei és teljesítménye című témakörben találja.
A visszaadott ROW_NUMBER() rangsorolási információk közvetlenül nem használhatók a WHERE záradékban. Egy származtatott tábla azonban az eredmény visszaadására ROW_NUMBER() használható, amely ezután megjelenhet a WHERE záradékban. Az alábbi lekérdezés például egy származtatott táblával adja vissza a ProductName és a UnitPrice oszlopokat az ROW_NUMBER() eredménnyel együtt, majd egy WHERE záradékkal csak azokat a termékeket adja vissza, amelyek árrangja 11 és 20 között van:
SELECT PriceRank, ProductName, UnitPrice
FROM
(SELECT ProductName, UnitPrice,
ROW_NUMBER() OVER(ORDER BY UnitPrice DESC) AS PriceRank
FROM Products
) AS ProductsWithRowNumber
WHERE PriceRank BETWEEN 11 AND 20
Ezt a koncepciót egy kicsit tovább bővítve ezt a megközelítést használhatjuk egy adott adatoldal lekérésére a kívánt kezdősorindex és a Maximális sorok érték alapján:
SELECT PriceRank, ProductName, UnitPrice
FROM
(SELECT ProductName, UnitPrice,
ROW_NUMBER() OVER(ORDER BY UnitPrice DESC) AS PriceRank
FROM Products
) AS ProductsWithRowNumber
WHERE PriceRank > <i>StartRowIndex</i> AND
PriceRank <= (<i>StartRowIndex</i> + <i>MaximumRows</i>)
Megjegyzés:
Ahogy az oktatóanyag későbbi részében látni fogjuk, az StartRowIndex ObjectDataSource által biztosított indexelés nullától kezdődik, míg az ROW_NUMBER() SQL Server 2005 által visszaadott érték indexelése 1-től kezdődik. Ezért a WHERE záradék azokat a rekordokat adja vissza, amelyek PriceRank szigorúan nagyobbak, mint StartRowIndex, és kisebbek vagy egyenlők StartRowIndex + MaximumRows.
Most, hogy bemutattuk, hogyan lehet egy adott adatlapot lekérni a Kezdősor indexe és a Maximális sorok érték alapján, ezt a logikát metódusokként kell megvalósítanunk a DAL-ban és a BLL-ben.
A lekérdezés létrehozásakor el kell döntenünk, hogy az eredmények milyen sorrendben lesznek rangsorolva; rendezzük a termékeket a nevük szerint betűrendbe. Ez azt jelenti, hogy az ebben az oktatóanyagban szereplő testreszabott lapozási megoldással nem tudunk olyan egyéni lapozható jelentést létrehozni, amely rendezhető is. A következő oktatóanyagban azonban látni fogjuk, hogyan biztosíthatók ezek a funkciók.
Az előző szakaszban a DAL metódust alkalmi SQL-utasításként hoztuk létre. Sajnos a TableAdapter varázsló által használt Visual Studio T-SQL-elemzője nem szereti a OVER függvény által használt ROW_NUMBER() szintaxist. Ezért ezt a DAL metódust tárolt eljárásként kell létrehoznunk. Válassza ki a Kiszolgálókezelőt a Nézet menüből (vagy nyomja le a Ctrl+Alt+S billentyűkombinációt), és bontsa ki a csomópontot NORTHWND.MDF . Új tárolt eljárás hozzáadásához kattintson a jobb gombbal a Tárolt eljárások csomópontra, és válassza az Új tárolt eljárás hozzáadása lehetőséget (lásd a 6. ábrát).
6. ábra: Egy új tárolt eljárás hozzáadása a termékek lapozásához
A tárolt eljárásnak két egész szám bemeneti paramétert kell elfogadnia - @startRowIndex és @maximumRows -, és a ROW_NUMBER() függvényt kell használnia, amely a ProductName mező alapján van rendezve, és csak azokat a sorokat adja vissza, amelyek nagyobbak a megadott @startRowIndex-nál, és kisebbek vagy egyenlőek a @startRowIndex + @maximumRow s-el. Írja be a következő szkriptet az új tárolt eljárásba, majd a Mentés ikonra kattintva adja hozzá a tárolt eljárást az adatbázishoz.
CREATE PROCEDURE dbo.GetProductsPaged
(
@startRowIndex int,
@maximumRows int
)
AS
SELECT ProductID, ProductName, SupplierID, CategoryID, QuantityPerUnit,
UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued,
CategoryName, SupplierName
FROM
(
SELECT ProductID, ProductName, SupplierID, CategoryID, QuantityPerUnit,
UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued,
(SELECT CategoryName
FROM Categories
WHERE Categories.CategoryID = Products.CategoryID) AS CategoryName,
(SELECT CompanyName
FROM Suppliers
WHERE Suppliers.SupplierID = Products.SupplierID) AS SupplierName,
ROW_NUMBER() OVER (ORDER BY ProductName) AS RowRank
FROM Products
) AS ProductsWithRowNumbers
WHERE RowRank > @startRowIndex AND RowRank <= (@startRowIndex + @maximumRows)
A tárolt eljárás létrehozása után szánjon egy kis időt a tesztelésre. Kattintson a jobb gombbal a GetProductsPaged tárolt eljárás nevére a Kiszolgálókezelőben, és válassza a Végrehajtás lehetőséget. A Visual Studio ezután kérni fogja a bemeneti paramétereket: @startRowIndex és @maximumRow-ket (lásd a 7. ábrát). Próbáljon ki különböző értékeket, és vizsgálja meg az eredményeket.
@startRowIndex és @maximumRows paraméterek" />
7. ábra: Adjon meg egy értéket a @startRowIndex és a @maximumRows paraméterek számára.
A bemeneti paraméterek értékeinek kiválasztása után a Kimenet ablak megjeleníti az eredményeket. A 8. ábra azt mutatja, hogy milyen eredmények keletkeznek, amikor mind a @startRowIndex és a @maximumRows paraméterek értékének 10-et adunk meg.
8. ábra: A második adatoldalon megjelenő rekordok visszaadása (ide kattintva megtekintheti a teljes méretű képet)
Ezzel a tárolt eljárással készen állunk a ProductsTableAdapter metódus létrehozására. Nyissa meg a Northwind.xsd Gépelt adatkészletet, kattintson a jobb gombbal a ProductsTableAdaptergombra, és válassza a Lekérdezés hozzáadása lehetőséget. A lekérdezés ad-hoc SQL-utasítással történő létrehozása helyett hozzon létre egy meglévő tárolt eljárást.
9. ábra: A DAL metódus létrehozása meglévő tárolt eljárás használatával
Ezután a rendszer arra kéri, hogy válassza ki a meghívandó tárolt eljárást. Válassza ki a GetProductsPaged tárolt eljárást a legördülő listából.
10. ábra: Válassza ki a GetProductsPaged tárolt eljárást a Drop-Down listából
A következő képernyő megkérdezi, hogy milyen típusú adatokat ad vissza a tárolt eljárás: táblázatos adatok, egyetlen érték vagy érték nélkül. Mivel a GetProductsPaged tárolt eljárás több rekordot is visszaadhat, azt jelzi, hogy táblázatos adatokat ad vissza.
11. ábra: Azt jelzi, hogy a tárolt eljárás táblázatos adatokat ad vissza
Végül adja meg a létrehozni kívánt metódusok nevét. A korábbi oktatóanyagokhoz hasonlóan hozzon létre metódusokat a DataTable kitöltése és a DataTable visszaadása funkcióval. Nevezze el az első metódust és a másodikat FillPagedGetProductsPaged.
12. ábra: A FillPaged és a GetProductsPaged metódus elnevezése
Amellett, hogy létrehoztunk egy DAL metódust, amely egy adott termékoldalt ad vissza, a BLL-ben is biztosítani kell az ilyen funkciókat. A DAL metódushoz hasonlóan a BLL GetProductsPaged metódusának két egész bemenetet kell elfogadnia a kezdősorindex és a maximális sorok megadásához, és csak azokat a rekordokat kell visszaadnia, amelyek a megadott tartományba tartoznak. Hozzon létre egy ilyen BLL-metódust a ProductsBLL osztályban, amely egyszerűen lehívja a DAL s GetProductsPaged metódust, például:
<System.ComponentModel.DataObjectMethodAttribute( _
System.ComponentModel.DataObjectMethodType.Select, False)> _
Public Function GetProductsPaged(startRowIndex As Integer, maximumRows As Integer) _
As Northwind.ProductsDataTable
Return Adapter.GetProductsPaged(startRowIndex, maximumRows)
End Function
A BLL-metódus bemeneti paramétereinek bármilyen nevet adhat, de amint hamarosan látni fogjuk, az ObjectDataSource ezen metódus használatának konfigurálásakor a startRowIndex és maximumRows használata megment minket a további munkával.
4. lépés: Az ObjectDataSource konfigurálása egyéni lapozás használatára
A rekordok egy adott részhalmazának elérésére szolgáló BLL- és DAL-metódusokkal készen állunk egy GridView-vezérlő létrehozására, amely egyéni lapozással böngészi a mögöttes rekordokat. Először nyissa meg a EfficientPaging.aspx lapot a PagingAndSorting mappában, vegyen fel egy GridView-t a lapra, és konfigurálja egy új ObjectDataSource-vezérlő használatára. A korábbi oktatóanyagokban gyakran konfiguráltuk az ObjectDataSource-t az ProductsBLL osztály s GetProducts metódusának használatára. Ezúttal azonban inkább a GetProductsPaged metódust szeretnénk használni, mivel a metódus az GetProducts adatbázis összes termékét visszaadja, míg GetProductsPaged a rekordoknak csak egy bizonyos részhalmazát adja vissza.
13. ábra: Az ObjectDataSource konfigurálása a ProductsBLL class s GetProductsPaged metódus használatára
Mivel írásvédett GridView-t hozunk létre, szánjon egy kis időt arra, hogy az INSERT, UPDATE és DELETE füleken a metódus legördülő listáját (Nincs) értékre állítsa.
Ezután az ObjectDataSource varázsló kéri a metódusok GetProductsPaged és startRowIndex a maximumRows bemeneti paraméterek értékeinek forrását. Ezeket a bemeneti paramétereket a GridView automatikusan beállítja, ezért egyszerűen hagyja a forráskészletet None értékre, és kattintson a Befejezés gombra.
14. ábra: A bemeneti paraméterforrásokat hagyja a "Nincs" értéken
Az ObjectDataSource varázsló befejezése után a GridView minden termékadatmezőhöz tartalmaz egy BoundField vagy CheckBoxField mezőt. Nyugodtan testre szabhatja a GridView megjelenését, ahogy látja. Úgy döntöttem, hogy csak a ProductName, CategoryName, SupplierName, , QuantityPerUnités UnitPrice BoundFields jelenik meg. Emellett úgy konfigurálja a GridView-t, hogy támogassa a lapozást az intelligens címkén található Lapozás engedélyezése jelölőnégyzet bejelölésével. A módosítások után a GridView és az ObjectDataSource deklaratív korrektúrának az alábbiakhoz hasonlóan kell kinéznie:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" AllowPaging="True">
<Columns>
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
<asp:BoundField DataField="CategoryName" HeaderText="Category"
ReadOnly="True" SortExpression="CategoryName" />
<asp:BoundField DataField="SupplierName" HeaderText="Supplier"
SortExpression="SupplierName" />
<asp:BoundField DataField="QuantityPerUnit" HeaderText="Qty/Unit"
SortExpression="QuantityPerUnit" />
<asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}"
HeaderText="Price" HtmlEncode="False" SortExpression="UnitPrice" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
OldValuesParameterFormatString="original_{0}" SelectMethod="GetProductsPaged"
TypeName="ProductsBLL">
<SelectParameters>
<asp:Parameter Name="startRowIndex" Type="Int32" />
<asp:Parameter Name="maximumRows" Type="Int32" />
</SelectParameters>
</asp:ObjectDataSource>
Ha azonban böngészőben látogatja meg az oldalt, a GridView nem található.
15. ábra: A GridView nem jelenik meg
A GridView hiányzik, mert az ObjectDataSource jelenleg 0 értéket használ mindkét és GetProductsPaged bemeneti paraméter értékeként.startRowIndexmaximumRows Ezért az eredményül kapott SQL-lekérdezés nem ad vissza rekordokat, ezért a GridView nem jelenik meg.
Ennek orvoslásához konfigurálnunk kell az ObjectDataSource-t egyéni lapozás használatára. Ez a következő lépésekben valósítható meg:
-
Állítsa be az ObjectDataSource tulajdonságot
EnablePagingtrueúgy, hogy az azt jelzi az ObjectDataSource-nak, hogy a két további paraméternek kell átadniaSelectMethod: az egyik a kezdősor indexének (StartRowIndexParameterName) megadásához, a másik pedig a maximális sorok (MaximumRowsParameterName) megadásához. -
Állítsa be az ObjectDataSource
StartRowIndexParameterNameésMaximumRowsParameterNametulajdonságokat megfelelően,StartRowIndexParameterNameésMaximumRowsParameterNametulajdonságok az egyéni lapozási célokra átadottSelectMethodbemeneti paraméterek nevét jelzik. Alapértelmezés szerint ezek a paraméternevekstartIndexRow, ésmaximumRowsezért a metódus BLL-ben való létrehozásakorGetProductsPagedezeket az értékeket használtam a bemeneti paraméterekhez. Ha úgy döntött, hogy a BLLGetProductsPagedmetódusának különböző paraméterneveit használja, példáulstartIndexésmaxRows, akkor az ObjectDataSourceStartRowIndexParameterNameésMaximumRowsParameterNametulajdonságait ennek megfelelően kell beállítania (mint például aStartRowIndexParameterNamestartIndex és aMaximumRowsParameterNamemaxRows esetében). -
Állítsa az ObjectDataSource tulajdonságát
SelectCountMethodannak a metódusnak a nevére, amely visszaadja a lapozás alatt álló rekordok teljes számát (TotalNumberOfProducts) emlékeztet arra, hogy azProductsBLLosztály sTotalNumberOfProductsmetódusa a lekérdezést végrehajtóSELECT COUNT(*) FROM ProductsDAL metódussal visszaadja a lapozás alatt álló rekordok teljes számát. Ezekre az információkra az ObjectDataSource-nak szüksége van a lapozófelület megfelelő megjelenítéséhez. -
Az
startRowIndexésmaximumRows<asp:Parameter>elemek eltávolítása az ObjectDataSource deklaratív jelöléséből az ObjectDataSource varázslón keresztüli konfigurálásakor a Visual Studio automatikusan hozzáadott két<asp:Parameter>elemet aGetProductsPagedmetódus bemeneti paramétereihez. A beállítássalEnablePagingtrueezek a paraméterek automatikusan átadásra kerülnek; ha a deklaratív szintaxisban is megjelennek, az ObjectDataSource négy paramétert próbál átadni aGetProductsPagedmetódusnak, két paramétert pedig aTotalNumberOfProductsmetódusnak. Ha elfelejti eltávolítani ezeket az<asp:Parameter>elemeket, amikor egy böngészőben látogatja meg az oldalt, hibaüzenet jelenik meg, például: ObjectDataSource "ObjectDataSource1" nem talál olyan nem általános metódust ,,TotalNumberOfProducts", amely paraméterekkel rendelkezik: startRowIndex, maximumRows.
A módosítások elvégzése után az ObjectDataSource deklaratív szintaxisának a következőképpen kell kinéznie:
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
OldValuesParameterFormatString="original_{0}" SelectMethod="GetProductsPaged"
TypeName="ProductsBLL" EnablePaging="True" SelectCountMethod="
TotalNumberOfProducts">
</asp:ObjectDataSource>
Vegye figyelembe, hogy a EnablePaging és SelectCountMethod tulajdonságok be lettek állítva, és a <asp:Parameter> elemek el lettek távolítva. A 16. ábrán a Tulajdonságok ablak képernyőképe látható a módosítások elvégzése után.
16. ábra: Egyéni lapozás használatához konfigurálja az ObjectDataSource vezérlőt
Miután végrehajtotta ezeket a módosításokat, látogasson el erre a lapra egy böngészőben. 10 terméket kell látnia, betűrendben rendezve. Szánjon egy kis időt arra, hogy egyszerre egy oldalon haladjon végig az adatokon. Bár nincs vizuális különbség a végfelhasználó szempontjából az alapértelmezett lapozás és az egyéni lapozás között, az egyéni lapozás hatékonyabb lapozása nagy mennyiségű adaton keresztül, mivel csak az adott laphoz megjelenítendő rekordokat kéri le.
17. ábra: A Termék neve alapján rendezett adatok egyéni lapozással lapozhatók (ide kattintva megtekintheti a teljes méretű képet)
Megjegyzés:
Egyéni lapozás esetén az ObjectDataSource SelectCountMethod által visszaadott oldalszámérték a GridView nézetállapotában lesz tárolva. Más GridView-változók a PageIndex, EditIndex, , SelectedIndexDataKeys gyűjtemény és így tovább vezérlőállapotban vannak tárolva, amely a GridView EnableViewState tulajdonság értékétől függetlenül megmarad. Mivel az PageCount érték nézetállapot használatával megmarad a postbackek között, az utolsó oldalra mutató hivatkozást tartalmazó lapozófelület használata esetén feltétlenül engedélyezni kell a GridView nézetállapotát. (Ha a lapozófelület nem tartalmaz közvetlen hivatkozást az utolsó lapra, letilthatja a nézet állapotát.)
Ha az utolsó oldalhivatkozásra kattint, az visszalépést okoz, és arra utasítja a GridView-t, hogy frissítse a tulajdonságát PageIndex . Ha az utolsó oldalhivatkozásra kattintanak, a GridView a PageIndex tulajdonságát egyel kisebb értékre állítja, mint a PageCount tulajdonsága. Ha a megtekintési állapot le van tiltva, az PageCount érték elveszik a visszalépések során, és a PageIndex rendszer a maximális egész számot rendeli hozzá. Ezután a GridView megkísérli meghatározni a kezdősor-indexet a PageSize és PageCount tulajdonságok megszorzásával. Ez azt eredményezi, OverflowException hogy a termék meghaladja a maximálisan megengedett egész számot.
Egyéni lapozás és rendezés implementálása
Az egyéni lapozás jelenlegi implementációja megköveteli, hogy a tárolt eljárás létrehozásakor GetProductsPaged statikusan meg kell adni azt a sorrendet, amellyel az adatok lapozhatók. Előfordulhat azonban, hogy a GridView intelligens címkéje a Lapozás engedélyezése beállítás mellett a Rendezés engedélyezése jelölőnégyzetet is tartalmazza. Sajnos a GridView rendezési támogatásának hozzáadása a jelenlegi egyéni lapozási implementációval csak az aktuálisan megtekintett adatoldalon rendezi a rekordokat. Ha például úgy konfigurálja a GridView-t, hogy támogassa a lapozást, majd amikor megtekinti az első adatoldalt, csökkenő sorrendben rendezi a termék nevét, az 1. oldalon megfordítja a termékek sorrendjét. A 18. ábrán látható, hogy a Carnarvon Tigers az első termék a fordított betűrendben történő rendezéskor, amely figyelmen kívül hagyja a Carnarvon Tigers után érkező további 71 terméket betűrendben; A rendezés csak az első oldalon lévő rekordokat veszi figyelembe.
18. ábra: Csak az aktuális lapon látható adatok rendezése történik (kattintson ide a teljes méretű kép megtekintéséhez)
A rendezés csak az aktuális adatoldalra vonatkozik, mert a rendezés az adatok BLL-metódusból való lekérése GetProductsPaged után történik, és ez a módszer csak az adott lap rekordjait adja vissza. A rendezés helyes implementálásához át kell adnunk a rendezési kifejezést a GetProductsPaged metódusnak, hogy az adatok megfelelően rangsorolhatók legyenek az adott adatoldal visszaadása előtt. Ezt a következő oktatóanyagban fogjuk látni.
Egyéni lapozás és törlés implementálása
Ha egy olyan GridView-ban engedélyezi a törlési funkciót, amelynek adatai egyéni lapozási technikákkal vannak lapozva, azt tapasztalhatja, hogy amikor az utolsó rekordot törli az utolsó oldalról, a GridView eltűnik ahelyett, hogy megfelelően csökkentené a GridView PageIndex. A hiba reprodukálásához engedélyezze az imént létrehozott oktatóanyag törlését. Lépjen az utolsó oldalra (9. oldal), ahol egyetlen terméknek kell megjelennie, mivel egyszerre 81 terméket, 10 terméket lapozunk. Törölje ezt a terméket.
Az utolsó termék törlésekor a GridView-nak automatikusan a nyolcadik oldalra kell lépnie, és az ilyen funkciók alapértelmezett lapozással jelennek meg. Egyéni lapozással azonban az utolsó oldalon lévő utolsó termék törlése után a GridView egyszerűen eltűnik a képernyőről. Ennek a pontos oka kissé meghaladja az oktatóanyag hatókörét; tekintse meg az egyéni lapozású GridView utolsó oldalának utolsó rekordjának törlése című részt a probléma forrásával kapcsolatos alacsony szintű részletekért. Összefoglalva ez a GridView által a Törlés gombra kattintáskor végrehajtott lépések következő sorozatának köszönhető:
- A rekord törlése
- Szerezze be a megadott
PageIndexésPageSizemegfelelő rekordokat a megjelenítéshez. - Ellenőrizze, hogy a
PageIndexlapszám nem haladja-e meg az adatforrásban található adatoldalak számát; ha igen, automatikusan korlátozza a GridView tulajdonságátPageIndex - A megfelelő adatoldal kötése a GridView-hoz a 2. lépésben beszerzett rekordok használatával
A probléma abból a tényből ered, hogy a 2. lépésben a PageIndex rekordok megjelenítéséhez használt adatok továbbra is az PageIndex utolsó oldalé, amelynek egyetlen rekordját éppen törölték. Ezért a 2. lépésben a rendszer nem ad vissza rekordokat, mivel az utolsó adatoldal már nem tartalmaz rekordokat. Ezután a 3. lépésben a GridView rájön, hogy a tulajdonsága PageIndex nagyobb, mint az adatforrásban lévő oldalak teljes száma (mivel az utolsó oldalon töröltük az utolsó rekordot), ezért a tulajdonsága PageIndex csökken. A 4. lépésben a GridView megpróbálja magát a 2. lépésben lekért adatokhoz kötni; a 2. lépésben azonban nem ad vissza rekordokat, ezért üres GridView-t eredményezett. Alapértelmezett lapozás esetén ez a probléma nem jelentkezik, mert a 2. lépésben az összes rekordot lekérik az adatforrásból.
Ennek kijavításához két lehetőségünk van. Az első egy eseménykezelő létrehozása a GridView eseménykezelőjének RowDeleted , amely meghatározza, hogy hány rekord jelent meg az imént törölt lapon. Ha csak egy rekord volt, akkor az imént törölt rekordnak kellett lennie az utolsónak, és meg kell csökkentenünk a GridView s PageIndex. Természetesen csak akkor szeretnénk frissíteni a PageIndex, ha a törlési művelet valóban sikeres volt, amit úgy határozhatunk meg, hogy a e.Exception tulajdonság null.
Ez a módszer azért működik, mert az 1. lépés után, de a PageIndex 2. lépés előtt frissíti. Ezért a 2. lépésben a megfelelő rekordhalmaz lesz visszaadva. Ehhez használja a következőhöz hasonló kódot:
Protected Sub GridView1_RowDeleted(sender As Object, e As GridViewDeletedEventArgs) _
Handles GridView1.RowDeleted
' If we just deleted the last row in the GridView, decrement the PageIndex
If e.Exception Is Nothing AndAlso GridView1.Rows.Count = 1 Then
' we just deleted the last row
GridView1.PageIndex = Math.Max(0, GridView1.PageIndex - 1)
End If
End Sub
Alternatív megoldásként hozzon létre egy eseménykezelőt az ObjectDataSource RowDeleted eseményéhez, és állítsa a AffectedRows tulajdonság értékét 1 értékre. Miután törölte a rekordot az 1. lépésben (de a 2. lépésben az adatok újbóli beolvasása előtt), a GridView frissíti a tulajdonságát PageIndex , ha a művelet egy vagy több sort érintett. A tulajdonságot azonban nem az ObjectDataSource állítja be, AffectedRows ezért a rendszer kihagyja ezt a lépést. A lépés végrehajtásának egyik módja a AffectedRows tulajdonság manuális beállítása, ha a törlési művelet sikeresen befejeződött. Ez a következő kóddal hajtható végre:
Protected Sub ObjectDataSource1_Deleted( _
sender As Object, e As ObjectDataSourceStatusEventArgs) _
Handles ObjectDataSource1.Deleted
' If we get back a Boolean value from the DeleteProduct method and it's true, then
' we successfully deleted the product. Set AffectedRows to 1
If TypeOf e.ReturnValue Is Boolean AndAlso CType(e.ReturnValue, Boolean) = True Then
e.AffectedRows = 1
End If
End Sub
Mindkét eseménykezelő kódja a példa kód mögötti osztályában EfficientPaging.aspx található.
Az alapértelmezett és az egyéni lapozás teljesítményének összehasonlítása
Mivel az egyéni lapozás csak a szükséges rekordokat kéri le, míg az alapértelmezett lapozás minden megtekintett lap összes rekordját visszaadja, egyértelmű, hogy az egyéni lapozás hatékonyabb az alapértelmezett lapozásnál. De mennyivel hatékonyabb az egyéni lapozás? Milyen teljesítménynövekedés tapasztalható az alapértelmezett lapozásról az egyéni lapozásra való áttéréssel?
Sajnos, itt nincs mindenkinek megfelelő megoldás. A teljesítménynövekedés számos tényezőtől függ, a legfontosabb kettő a lapozás alatt álló rekordok száma, valamint az adatbázis-kiszolgálóra helyezett terhelés, valamint a webkiszolgáló és az adatbázis-kiszolgáló közötti kommunikációs csatornák. Néhány tucat rekordot tartalmazó kis táblák esetében a teljesítménybeli különbség elhanyagolható lehet. A nagy táblák esetében, ahol több ezer-százezer sor van, a teljesítménybeli különbség azonban akut.
Az "Egyéni lapozás a ASP.NET 2.0-s verziójában az SQL Server 2005-ben" című cikkem tartalmaz néhány teljesítménytesztet, amelyek a két lapozási technika teljesítménybeli különbségeit mutatták be, amikor egy 50 000 rekordot tartalmazó adatbázistáblán lapoznak. Ezekben a tesztekben megvizsgáltam mind az SQL Server szintjén (az SQL Profiler használatával), mind a ASP.NET oldalon a lekérdezés végrehajtásának idejét ASP.NET nyomkövetési funkciók használatával. Ne feledje, hogy ezeket a teszteket egyetlen aktív felhasználóval futtattam a fejlesztői dobozomon, ezért tudománytalanok, és nem utánozzák a webhely tipikus terhelési mintáit. Az eredmények ettől függetlenül jól szemléltetik az alapértelmezett és egyéni lapozás végrehajtási idejének relatív különbségeit, amikor elég nagy mennyiségű adattal dolgoznak.
| Átl. Időtartam (mp) | Olvas | |
|---|---|---|
| Alapértelmezett lapozási SQL Profiler | 1.411 | 383 |
| Testreszabott lapozás SQL profilozó | 0.002 | 29 |
| Alapértelmezett lapozási ASP.NET nyomkövetés | 2.379 | N/A |
| Egyéni lapozási ASP.NET nyomkövetés | 0.029 | N/A |
Mint látható, egy adott adatoldal beolvasása átlagosan 354-rel kevesebb olvasást igényelt, és az idő töredékében fejeződött be. Az ASP.NET oldalon egyedi beállításokkal az oldal közel 1/100 idő alatt jelent meg, mint az alapértelmezett lapozásnál.
Összefoglalás
Az alapértelmezett lapozást könnyű megvalósítani: csak be kell jelölni a Lapozás engedélyezése jelölőnégyzetet az adatwebvezérlő intelligens címkéjében, de az ilyen egyszerűség a teljesítmény rovására mehet. Az alapértelmezett lapozás esetén, amikor egy felhasználó bármilyen adatlapot kér, a rendszer minden rekordot visszaad, annak ellenére, hogy csak a töredékük jelenik meg. A teljesítményterhelés elleni küzdelem érdekében az ObjectDataSource alternatív lapozási lehetőséget kínál egyéni lapozási lehetőséggel.
Bár az egyéni lapozás javítja az alapértelmezett lapozás teljesítményproblémáit azáltal, hogy csak a megjelenítendő rekordokat kéri le, az egyéni lapozás implementálása bonyolultabb feladat. Először meg kell írni egy lekérdezést, amely megfelelően (és hatékonyan) fér hozzá a kért rekordok adott részhalmazához. Ez többféleképpen is elvégezhető; Ebben az oktatóanyagban megvizsgáltuk, hogy az SQL Server 2005 új ROW_NUMBER() függvényével rangsorolja az eredményeket, majd csak azokat az eredményeket adja vissza, amelyek rangsorolása egy megadott tartományba esik. Emellett egy olyan eszközt is hozzá kell adnunk, amin a lapozás alatt álló rekordok teljes száma meghatározható. Ezeknek a DAL- és BLL-metódusoknak a létrehozása után konfigurálnunk kell az ObjectDataSource-t is, hogy meg tudja állapítani, hány rekordot szeretne átlapolni, és megfelelően át tudja adni a kezdősorindexet és a sorok maximális értékét a BLL-nek.
Bár az egyéni lapozás megvalósítása számos lépést igényel, és közel sem olyan egyszerű, mint az alapértelmezett lapozás, az egyéni lapozásra szükség van, ha elég nagy mennyiségű adatot lapoznak. Ahogy a vizsgált eredmények is mutatták, az egyéni lapozás másodpercek alatt képes kikapcsolni a ASP.NET oldal renderelési idejét, és egy vagy több nagyságrenddel könnyebbé teheti az adatbázis-kiszolgáló terhelését.
Boldog programozást!
Tudnivalók a szerzőről
Scott Mitchell, hét ASP/ASP.NET-könyv szerzője és a 4GuysFromRolla.com alapítója, 1998 óta dolgozik a Microsoft webtechnológiáival. Scott független tanácsadóként, edzőként és íróként dolgozik. Legújabb könyve Sams Teach Yourself ASP.NET 2.0 24 óra alatt. Ő itt elérhető mitchell@4GuysFromRolla.com.