Sdílet prostřednictvím


Účinné stránkování velkých objemů dat (VB)

Scott Mitchell

Stáhnout PDF

Výchozí možnost stránkování ovládacího prvku prezentace dat není vhodná při práci s velkými objemy dat, protože jeho podkladový ovládací prvek zdroje dat načítá všechny záznamy, i když se zobrazuje jenom podmnožina dat. Za takových okolností se musíme obrátit na vlastní stránkování.

Úvod

Jak jsme probrali v předchozím kurzu, stránkování je možné implementovat jedním ze dvou způsobů:

  • Výchozí stránkování lze implementovat jednoduše zaškrtnutím povolit stránkování možnost v inteligentní značce webového ovládacího prvku dat; Při každém prohlížení stránky dat však ObjectDataSource načte všechny záznamy, i když se na stránce zobrazí pouze jejich podmnožina.
  • Vlastní stránkování zlepšuje výkon výchozího stránkování načtením pouze těch záznamů z databáze, které je třeba zobrazit pro konkrétní stránku dat požadovaných uživatelem; Implementace vlastního stránkování ale vyžaduje trochu větší úsilí než výchozí stránkování.

Vzhledem k snadné implementaci stačí zaškrtnout políčko a máte hotovo! výchozí stránkování je atraktivní možnost. Jeho naivní přístup při načítání všech záznamů však z něj dělá nepůletelnou volbu při stránkování dostatečně velkých objemů dat nebo pro weby s mnoha souběžnými uživateli. Za takových okolností se musíme obrátit na vlastní stránkování, abychom zajistili responzivní systém.

Výzvou vlastního stránkování je schopnost napsat dotaz, který vrátí přesnou sadu záznamů potřebnou pro konkrétní stránku dat. Microsoft SQL Server 2005 naštěstí poskytuje nové klíčové slovo pro hodnocení výsledků, které nám umožňuje napsat dotaz, který dokáže efektivně načíst správnou podmnožinu záznamů. V tomto kurzu uvidíme, jak používat toto nové klíčové slovo SQL Server 2005 k implementaci vlastního stránkování v ovládacím prvku GridView. Uživatelské rozhraní pro vlastní stránkování je stejné jako u výchozího stránkování, ale krokování z jedné stránky na druhou pomocí vlastního stránkování může být o několik řádů rychlejší než výchozí stránkování.

Poznámka

Přesný nárůst výkonu, který vlastní stránkování vykazuje, závisí na celkovém počtu stránkovaných záznamů a zatížení databázového serveru. Na konci tohoto kurzu se podíváme na několik hrubých metrik, které ukazují výhody výkonu dosaženého vlastním stránkováním.

Krok 1: Vysvětlení vlastního procesu stránkování

Při stránkování dat závisí přesné záznamy zobrazené na stránce na stránce požadovaných dat a počtu zobrazených záznamů na stránce. Představte si například, že jsme chtěli procházet 81 produkty a zobrazovat 10 produktů na stránku. Při prohlížení první stránky chceme produkty 1 až 10; při prohlížení druhé stránky by nás zajímaly produkty 11 až 20 atd.

Existují tři proměnné, které určují, jaké záznamy se mají načíst a jak se má stránkovací rozhraní vykreslit:

  • Start Row Index index prvního řádku na stránce dat k zobrazení; Tento index lze vypočítat vynásobením indexu stránky záznamy, které se zobrazí na stránce, a přidáním jednoho indexu. Například při stránkování záznamů 10 najednou, pro první stránku (jejíž index stránky je 0) je index počátečního řádku 0 × 10 + 1 nebo 1; pro druhou stránku (jejíž index stránky je 1) je index počátečního řádku 1 × 10 + 1 nebo 11.
  • Maximum Rows (Maximální počet řádků ): Maximální počet záznamů, které se mají zobrazit na stránce. Tato proměnná se označuje jako maximální počet řádků, protože na poslední stránce může být vráceno méně záznamů, než je velikost stránky. Například při stránkování 81 produktů s 10 záznamy na stránku bude devátá a poslední stránka obsahovat pouze jeden záznam. Žádná stránka ale nebude zobrazovat více záznamů, než je hodnota Maximální počet řádků.
  • Total Record Count Celkový počet záznamů, které jsou stránkovány. I když tato proměnná není potřebná k určení toho, jaké záznamy se mají načíst pro danou stránku, diktuje stránkovací rozhraní. Pokud se například stránkuje 81 produktů, stránkovací rozhraní ví, že v uživatelském rozhraní stránkování zobrazí devět čísel stránek.

Při výchozím stránkování se index počátečního řádku vypočítá jako součin indexu stránky a velikost stránky plus jedna, zatímco maximální počet řádků je jednoduše velikost stránky. Vzhledem k tomu, že výchozí stránkování při vykreslování libovolné stránky dat načte všechny záznamy z databáze, je znám index pro každý řádek, takže přechod na počáteční řádek index řádku je triviální úkol. Celkový počet záznamů je navíc snadno dostupný, protože se jedná jednoduše o počet záznamů v tabulce DataTable (nebo jakýkoli objekt, který se používá k uložení výsledků databáze).

Vzhledem k proměnným Index počátečního řádku a Maximální počet řádků musí vlastní implementace stránkování vracet pouze přesnou podmnožinu záznamů počínaje indexem počátečního řádku a až do maximálního počtu řádků záznamů po této hodnotě. Vlastní stránkování má dva problémy:

  • Musíme být schopni efektivně přidružit index řádků ke každému řádku v celých stránkovaných datech, abychom mohli začít vracet záznamy v zadaném indexu počátečního řádku.
  • Musíme zadat celkový počet záznamů, které jsou stránkovány.

V dalších dvou krocích prozkoumáme skript SQL, který je potřeba k reakci na tyto dva výzvy. Kromě skriptu SQL budeme také potřebovat implementovat metody v DAL a BLL.

Krok 2: Vrácení celkového počtu stránkovaných záznamů

Než prozkoumáme, jak načíst přesnou podmnožinu záznamů pro zobrazenou stránku, podívejme se nejprve na to, jak vrátit celkový počet záznamů, které jsou stránkovány. Tyto informace jsou potřeba ke správné konfiguraci uživatelského rozhraní stránkování. Celkový počet záznamů vrácených konkrétním dotazem SQL je možné získat pomocí COUNT agregační funkce. Například k určení celkového počtu záznamů v Products tabulce můžeme použít následující dotaz:

SELECT COUNT(*)
FROM Products

Pojďme do dal přidat metodu, která vrátí tyto informace. Konkrétně vytvoříme metodu DAL s názvem TotalNumberOfProducts() , která provede SELECT výše uvedený příkaz.

Začněte otevřením Northwind.xsd souboru Typed DataSet ve App_Code/DAL složce . Potom klikněte pravým tlačítkem na ProductsTableAdapter položku v Designer a zvolte Přidat dotaz. Jak jsme viděli v předchozích kurzech, umožní nám to přidat novou metodu do DAL, která při vyvolání provede konkrétní příkaz SQL nebo uloženou proceduru. Stejně jako u našich metod TableAdapter v předchozích kurzech se v tomto případě rozhodněte, že použijete příkaz SQL ad hoc.

Použití ad hoc příkazu SQL

Obrázek 1: Použití ad hoc příkazu SQL

Na další obrazovce můžeme určit, jaký typ dotazu se má vytvořit. Vzhledem k tomu, že tento dotaz vrátí jednu skalární hodnotu, zvolte SELECT možnost , která vrátí hodnotu singe, celkový počet záznamů v Products tabulce.

Nakonfigurujte dotaz tak, aby používal příkaz SELECT, který vrací jednu hodnotu.

Obrázek 2: Konfigurace dotazu tak, aby používal příkaz SELECT, který vrací jednu hodnotu

Po určení typu dotazu, který se má použít, musíme dále zadat dotaz.

Použití dotazu SELECT COUNT(*) FROM Products

Obrázek 3: Použití dotazu SELECT COUNT(*) FROM Products

Nakonec zadejte název metody . Jak je uvedeno výše, použádejme .TotalNumberOfProducts

Pojmenujte metodu DAL TotalNumberOfProducts.

Obrázek 4: Pojmenování metody DAL TotalNumberOfProducts

Po kliknutí na Dokončit průvodce přidá metodu TotalNumberOfProducts do souboru DAL. Skalární návratové metody v DAL vrací typy s možnou hodnotou null pro případ, že by výsledek dotazu SQL byl NULL. Náš COUNT dotaz ale vždy vrátí hodnotu, která neníNULL . Bez ohledu na to vrátí metoda DAL celé číslo s možnou hodnotou null.

Kromě metody DAL potřebujeme také metodu v BLL. ProductsBLL Otevřete soubor třídy a přidejte metoduTotalNumberOfProducts, která jednoduše volá metodu DAL sTotalNumberOfProducts:

Public Function TotalNumberOfProducts() As Integer
    Return Adapter.TotalNumberOfProducts().GetValueOrDefault()
End Function

Metoda DAL s TotalNumberOfProducts vrátí celé číslo s možnou hodnotou null, ale vytvořili jsme metodu ProductsBLL třídy s TotalNumberOfProducts , aby vrátila standardní celé číslo. Proto potřebujeme, aby ProductsBLL metoda třídy s TotalNumberOfProducts vrátila část hodnoty celého čísla s možnou hodnotou null vrácenou metodou DAL s TotalNumberOfProducts . Volání GetValueOrDefault() vrátí hodnotu celého čísla s možnou hodnotou null, pokud existuje. Pokud je nullcelé číslo s možnou hodnotou null , vrátí výchozí celočíselnou hodnotu 0.

Krok 3: Vrácení přesné podmnožině záznamů

Naším dalším úkolem je vytvořit metody v DAL a BLL, které přijímají proměnné Index počátečního řádku a Maximální počet řádků uvedené výše a vrátí příslušné záznamy. Než to uděláme, podívejme se nejprve na potřebný skript SQL. Problémem, kterému čelíme, je, že musíme být schopni efektivně přiřadit index ke každému řádku v rámci celého stránkování výsledků, abychom mohli vrátit pouze ty záznamy počínaje indexem počátečního řádku (až do maximálního počtu záznamů).

To není problém, pokud už v tabulce databáze existuje sloupec, který slouží jako index řádků. Na první pohled se můžeme domnívat, že Products pole tabulky ProductID s bude stačit, protože první produkt má ProductID hodnotu 1, druhý hodnotu 2 atd. Odstranění produktu však ponechá mezeru v sekvenci, což tento přístup zruší.

K efektivnímu přidružení indexu řádků k datům, která se mají procházet stránkami, se používají dvě obecné techniky, které umožňují načtení přesné podmnožiny záznamů:

  • Při použití SQL Server 2005 s ROW_NUMBER() Klíčové slovo nové pro SQL Server 2005 klíčové ROW_NUMBER() slovo přidruží ke každému vráceným záznamům hodnocení na základě nějakého pořadí. Toto pořadí lze použít jako index řádku pro každý řádek.

  • Použití proměnné tabulky a SET ROWCOUNT SQL Server sSET ROWCOUNT příkaz lze použít k určení celkového počtu záznamů, které má dotaz zpracovat před ukončením; Proměnné tabulky jsou místní proměnné T-SQL, které mohou obsahovat tabulková data, podobné dočasným tabulkám. Tento přístup funguje stejně dobře s Microsoft SQL Server 2005 a SQL Server 2000 (zatímco ROW_NUMBER() přístup funguje pouze s SQL Server 2005).

    Cílem je vytvořit proměnnou tabulky, která obsahuje IDENTITY sloupec a sloupce pro primární klíče tabulky, jejíž data jsou stránkována. Dále se obsah tabulky, jejíž data jsou stránkována, vypíše do proměnné tabulky, čímž se přidružuje sekvenční index řádků (prostřednictvím IDENTITY sloupce) pro každý záznam v tabulce. Jakmile je proměnná tabulky naplněna, SELECT je možné provést příkaz pro proměnnou tabulky, který je spojený s podkladovou tabulkou, aby se vytáhly konkrétní záznamy. Příkaz SET ROWCOUNT slouží k inteligentnímu omezení počtu záznamů, které je potřeba vypsat do proměnné tabulky.

    Efektivita tohoto přístupu je založená na požadovaném čísle stránky, protože hodnotě SET ROWCOUNT je přiřazena hodnota Index počátečního řádku plus Maximální počet řádků. Tento přístup je velmi efektivní při stránkování na stránkách s nízkým číslem, jako je několik prvních stránek dat. Při načítání stránky blízko konce ale vykazuje výchozí výkon podobný stránkování.

Tento kurz implementuje vlastní stránkování pomocí klíčového ROW_NUMBER() slova . Další informace o použití tabulkové proměnné a SET ROWCOUNT techniky najdete v tématu Efektivnější metoda stránkování prostřednictvím velkých sad výsledků.

Klíčové ROW_NUMBER() slovo přidružuje pořadí ke každému záznamu vráceným pro konkrétní řazení pomocí následující syntaxe:

SELECT columnList,
       ROW_NUMBER() OVER(orderByClause)
FROM TableName

ROW_NUMBER() vrátí číselnou hodnotu, která určuje pořadí pro každý záznam s ohledem na uvedené pořadí. Abychom například viděli pořadí jednotlivých produktů seřazených od nejdražšího po nejnižší, mohli bychom použít následující dotaz:

SELECT ProductName, UnitPrice,
       ROW_NUMBER() OVER(ORDER BY UnitPrice DESC) AS PriceRank
FROM Products

Obrázek 5 ukazuje výsledky tohoto dotazu při spuštění okna dotazu v sadě Visual Studio. Všimněte si, že produkty jsou seřazené podle ceny spolu s pořadím cen pro každý řádek.

Cenové pořadí je zahrnuto pro každý vrácený záznam.

Obrázek 5: Pořadí cen je zahrnuto pro každý vrácený záznam

Poznámka

ROW_NUMBER()je jen jednou z mnoha nových funkcí řazení, které jsou k dispozici v SQL Server 2005. Podrobnější diskuzi o nástroji a dalších funkcích ROW_NUMBER()řazení najdete v dokumentaci ROW_NUMBER.

Při řazení výsledků podle zadaného ORDER BY sloupce v klauzuli OVER (UnitPriceve výše uvedeném příkladu) musí SQL Server výsledky seřadit. Jedná se o rychlou operaci, pokud existuje skupinový index nad sloupci nebo sloupci, podle kterého jsou výsledky seřazeny, nebo pokud existuje krycí index, ale jinak může být nákladnější. Pokud chcete zlepšit výkon u dostatečně velkých dotazů, zvažte přidání nes clusterovaného indexu pro sloupec, podle kterého jsou výsledky seřazené podle. Podrobnější informace o výkonu najdete v tématu Řazení funkcí a výkonu v SQL Server 2005.

Informace o pořadí vrácené nástrojem ROW_NUMBER() nelze přímo použít v klauzuli WHERE . K vrácení výsledku ROW_NUMBER() však lze použít odvozenou tabulku, která se pak může zobrazit v klauzuli WHERE . Následující dotaz například používá odvozenou tabulku k vrácení sloupců ProductName a UnitPrice spolu s ROW_NUMBER() výsledkem a pak použije WHERE klauzuli, která vrátí pouze produkty, jejichž pořadí cen je mezi 11 a 20:

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

Když tento koncept ještě trochu rozšíříme, můžeme tento přístup využít k načtení konkrétní stránky dat s požadovanými hodnotami Index počátečního řádku a Maximální počet řádků:

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>)

Poznámka

Jak uvidíme později v tomto kurzu, StartRowIndex hodnota zadaná objektem ObjectDataSource je indexována od nuly, zatímco ROW_NUMBER() hodnota vrácená SQL Server 2005 je indexována od 1. Proto klauzule WHERE vrátí záznamy, u kterých PriceRank je přísně větší než StartRowIndex a menší než nebo rovno + StartRowIndexMaximumRows .

Teď, když jsme probrali, jak ROW_NUMBER() se dá použít k načtení konkrétní stránky dat vzhledem k hodnotám Spustit index řádků a Maximální počet řádků, teď musíme tuto logiku implementovat jako metody v DAL a BLL.

Při vytváření tohoto dotazu musíme rozhodnout o pořadí, podle kterého budou výsledky seřazeny. nechte produkty seřadit podle jejich názvu v abecedním pořadí. To znamená, že s implementací vlastního stránkování v tomto kurzu nebudeme moct vytvořit vlastní stránkovanou sestavu, kterou lze také seřadit. V dalším kurzu se ale podíváme, jak se takové funkce dají poskytovat.

V předchozí části jsme vytvořili metodu DAL jako ad hoc příkaz SQL. Analyzátor T-SQL v sadě Visual Studio, který používá průvodce TableAdapter, se bohužel nelíbí OVER syntaxi používané ROW_NUMBER() funkcí. Proto musíme tuto metodu DAL vytvořit jako uloženou proceduru. V nabídce Zobrazení vyberte Průzkumníka serveru (nebo stiskněte Ctrl+Alt+S) a rozbalte NORTHWND.MDF uzel. Pokud chcete přidat novou uloženou proceduru, klikněte pravým tlačítkem na uzel Uložené procedury a zvolte Přidat novou uloženou proceduru (viz Obrázek 6).

Přidání nové uložené procedury pro stránkování prostřednictvím produktů

Obrázek 6: Přidání nové uložené procedury pro stránkování prostřednictvím produktů

Tato uložená procedura by měla přijímat dva celočíselné vstupní parametry – a používat funkci seřazenou podle ProductName pole, která vrací pouze řádky větší než zadané @startRowIndex a menší než nebo rovno + @maximumRow@startRowIndexs.ROW_NUMBER()@maximumRows@startRowIndex Do nové uložené procedury zadejte následující skript a kliknutím na ikonu Uložit přidejte uloženou proceduru do databáze.

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)

Po vytvoření uložené procedury si ji chvíli otestujte. V Průzkumníku GetProductsPaged serveru klikněte pravým tlačítkem na název uložené procedury a zvolte možnost Execute (Spustit). Visual Studio vás pak vyzve k zadání vstupních parametrů @startRowIndex a ( @maximumRow viz Obrázek 7). Zkuste různé hodnoty a prozkoumejte výsledky.

Zadejte hodnotu pro <span class=@startRowIndex and @maximumRows Parameters" />

Obrázek 7: Zadejte hodnotu parametrů @startRowIndex a @maximumRows

Po výběru těchto hodnot vstupních parametrů se v okně Výstup zobrazí výsledky. Obrázek 8 ukazuje výsledky při předání hodnoty 10 parametrů a @startRowIndex@maximumRows .

Vrátí se záznamy, které se zobrazí na druhé stránce dat.

Obrázek 8: Vrátí se záznamy, které se zobrazí na druhé stránce dat (kliknutím zobrazíte obrázek v plné velikosti).

Po vytvoření této uložené procedury jsme připraveni vytvořit metodu ProductsTableAdapter . Northwind.xsd Otevřete sadu Typed DataSet, klikněte pravým tlačítkem na ProductsTableAdaptera zvolte možnost Přidat dotaz. Místo vytvoření dotazu pomocí ad hoc příkazu SQL ho vytvořte pomocí existující uložené procedury.

Vytvoření metody DAL pomocí existující uložené procedury

Obrázek 9: Vytvoření metody DAL pomocí existující uložené procedury

Dále se zobrazí výzva k výběru uložené procedury, která se má vyvolat. V rozevíracím seznamu vyberte uloženou GetProductsPaged proceduru.

V seznamu Drop-Down zvolte uloženou proceduru GetProductsPaged.

Obrázek 10: Výběr uložené procedury GetProductsPaged ze seznamu Drop-Down

Na další obrazovce se zobrazí dotaz, jaký druh dat uložená procedura vrací: tabulková data, jedna hodnota nebo žádná hodnota. Vzhledem k tomu, že uložená procedura GetProductsPaged může vrátit více záznamů, uveďte, že vrací tabulková data.

Označení, že uložená procedura vrací tabulková data

Obrázek 11: Označení, že uložená procedura vrací tabulková data

Nakonec uveďte názvy metod, které chcete vytvořit. Stejně jako v předchozích kurzech, pokračujte vytvořením metod pomocí vyplnění tabulky DataTable a Vrácení dataTable. Pojmenujte první metodu FillPaged a druhou GetProductsPagedmetodu .

Pojmenujte metody FillPaged a GetProductsPaged.

Obrázek 12: Pojmenujte metody FillPaged a GetProductsPaged.

Kromě vytvoření metody DAL, která vrací konkrétní stránku produktů, musíme také poskytnout tyto funkce v BLL. Stejně jako metoda DAL musí metoda GetProductsPaged BLL přijímat dva celočíselné vstupy pro určení indexu počátečního řádku a maximálního počtu řádků a musí vracet pouze ty záznamy, které spadají do zadaného rozsahu. Vytvořte takovou metodu BLL ve třídě ProductsBLL, která pouze volá metodu DAL s GetProductsPaged, například takto:

<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

Můžete použít libovolný název vstupních parametrů metody BLL, ale jak uvidíme za chvíli, volba použít startRowIndex a maximumRows ušetřit nám další část práce při konfiguraci ObjectDataSource pro použití této metody.

Krok 4: Konfigurace objektu ObjectDataSource pro použití vlastního stránkování

Po dokončení metod BLL a DAL pro přístup k určité podmnožině záznamů jsme připraveni vytvořit ovládací prvek GridView, který bude stránkovat jeho podkladové záznamy pomocí vlastního stránkování. Začněte tím, že EfficientPaging.aspx otevřete stránku ve PagingAndSorting složce, přidáte na stránku GridView a nakonfigurujete ji tak, aby používala nový ovládací prvek ObjectDataSource. V našich předchozích kurzech jsme často měli ObjectDataSource nakonfigurovaný tak, aby používal metodu ProductsBLL třídy s GetProducts . Tentokrát ale chceme místo toho použít metodu GetProductsPaged , protože GetProducts metoda vrací všechny produkty v databázi, zatímco GetProductsPaged vrací jenom určitou podmnožinu záznamů.

Nakonfigurujte ObjectDataSource tak, aby používal metodu GetProductsPaged třídy ProductsBLL s.

Obrázek 13: Konfigurace objektu ObjectDataSource pro použití metody GetProductsPaged třídy ProductsBLL

Vzhledem k tomu, že vytváříme GridView jen pro čtení, chvíli trvá, než nastavíte rozevírací seznam metody na kartách INSERT, UPDATE a DELETE na (Žádné).

Dále nás průvodce ObjectDataSource vyzve k zadání zdrojů GetProductsPaged hodnot metod s startRowIndex a maximumRows vstupních parametrů. Tyto vstupní parametry budou ve skutečnosti nastaveny gridView automaticky, takže jednoduše nechejte zdroj nastavený na Žádný a klikněte na Dokončit.

Nechejte zdroje vstupních parametrů jako Žádné.

Obrázek 14: Nechejte zdroje vstupních parametrů jako Žádné

Po dokončení průvodce ObjectDataSource bude GridView obsahovat BoundField nebo CheckBoxField pro každé z datových polí produktu. Nebojte se přizpůsobit vzhled GridView podle potřeby. Rozhodl(a) jsem se zobrazit pouze ProductNamepole , CategoryName, SupplierName, QuantityPerUnita UnitPrice BoundFields. Také nakonfigurujte GridView tak, aby podporoval stránkování zaškrtnutím políčka Povolit stránkování v inteligentní značce. Po těchto změnách by deklarativní značky GridView a ObjectDataSource měly vypadat podobně jako následující:

<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>

Pokud ale stránku navštívíte prostřednictvím prohlížeče, GridView není místo, kde se má najít.

Objekt GridView se nezobrazuje.

Obrázek 15: Zobrazení mřížky se nezobrazuje

Objekt GridView chybí, protože ObjectDataSource aktuálně používá hodnotu 0 jako hodnoty vstupních GetProductsPagedstartRowIndex parametrů a maximumRows . Proto výsledný dotaz SQL nevrací žádné záznamy, a proto gridView se nezobrazí.

Abychom tento problém napravili, musíme nakonfigurovat ObjectDataSource tak, aby používal vlastní stránkování. To lze provést v následujících krocích:

  1. Nastavte vlastnost ObjectDataSource s EnablePaging na true hodnotu, která značí objektu ObjectDataSource, že musí předat SelectMethod dva další parametry: jeden pro určení indexu počátečního řádku (StartRowIndexParameterName) a druhý pro určení maximálního počtu řádků (MaximumRowsParameterName).
  2. Nastavte ObjectDataSource s StartRowIndexParameterName a MaximumRowsParameterName Properties Podle tohoStartRowIndexParameterName vlastnosti a MaximumRowsParameterName označují názvy vstupních parametrů předaných do objektu SelectMethod pro účely vlastního stránkování. Ve výchozím nastavení jsou startIndexRow tyto názvy parametrů a maximumRows, což je důvod, proč jsem při vytváření GetProductsPaged metody v BLL použil tyto hodnoty pro vstupní parametry. Pokud jste se rozhodli použít jiné názvy parametrů pro metodu BLL s GetProductsPaged , například startIndex a maxRows, museli byste odpovídajícím způsobem nastavit vlastnosti ObjectDataSource s StartRowIndexParameterName a MaximumRowsParameterName (například startIndex pro StartRowIndexParameterName a maxRows pro MaximumRowsParameterName).
  3. Nastavte Vlastnost ObjectDataSource s SelectCountMethod na Název metody, která vrací celkový počet záznamů, které jsou stránkovány (TotalNumberOfProducts), vzpomeňte si, že ProductsBLL metoda třídy s TotalNumberOfProducts vrací celkový počet záznamů stránkovaných pomocí metody DAL, která provádí SELECT COUNT(*) FROM Products dotaz. Tyto informace potřebuje ObjectDataSource, aby bylo možné správně vykreslit stránkovací rozhraní.
  4. startRowIndex Odeberte elementy a maximumRows<asp:Parameter> z deklarativních značek ObjectDataSource při konfiguraci ObjectDataSource prostřednictvím průvodce, Visual Studio automaticky přidal dva <asp:Parameter> prvky pro GetProductsPaged vstupní parametry metody s. EnablePaging Nastavením na true, budou tyto parametry předány automaticky; pokud se zobrazí také v deklarativní syntaxi, ObjectDataSource se pokusí předat čtyři parametry GetProductsPaged metodě a dva parametry do TotalNumberOfProducts metody. Pokud zapomenete tyto <asp:Parameter> prvky odebrat, při návštěvě stránky v prohlížeči se zobrazí chybová zpráva typu ObjectDataSource ObjectDataSource1 nemohl najít negenerovou metodu TotalNumberOfProducts s parametry: startRowIndex, maximumRows.

Po provedení těchto změn by deklarativní syntaxe ObjectDataSource měla vypadat takto:

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    OldValuesParameterFormatString="original_{0}" SelectMethod="GetProductsPaged"
    TypeName="ProductsBLL" EnablePaging="True" SelectCountMethod="
    TotalNumberOfProducts">
</asp:ObjectDataSource>

Všimněte si EnablePaging , že vlastnosti a SelectCountMethod byly nastaveny a <asp:Parameter> prvky byly odebrány. Obrázek 16 ukazuje snímek obrazovky okno Vlastnosti po provedení těchto změn.

Pokud chcete použít vlastní stránkování, nakonfigurujte ovládací prvek ObjectDataSource.

Obrázek 16: Pokud chcete použít vlastní stránkování, nakonfigurujte ovládací prvek ObjectDataSource.

Po provedení těchto změn přejděte na tuto stránku prostřednictvím prohlížeče. Měli byste vidět 10 produktů seřazených abecedně. Chvíli si prohlédněte data po jednotlivých stránkách. I když z pohledu koncového uživatele není žádný vizuální rozdíl mezi výchozím stránkováním a vlastním stránkováním, vlastní stránkování efektivněji stránkuje velké objemy dat, protože načítá pouze ty záznamy, které je potřeba zobrazit pro danou stránku.

Data seřazená podle názvu produktu se stránkují pomocí vlastního stránkování.

Obrázek 17: Data seřazená podle názvu produktu jsou stránkována pomocí vlastního stránkování (kliknutím zobrazíte obrázek v plné velikosti).

Poznámka

Při vlastním stránkování je hodnota počtu stránek vrácená ObjectDataSource SelectCountMethod uložena ve stavu zobrazení GridView. Jiné proměnné PageIndexGridView , , EditIndexSelectedIndex, DataKeys kolekce a tak dále jsou uloženy ve stavu ovládacího prvku, který je trvalý bez ohledu na hodnotu vlastnosti GridViewEnableViewState. Vzhledem k tomu, že PageCount hodnota je zachována napříč postbacky pomocí stavu zobrazení, při použití stránkovací rozhraní, které obsahuje odkaz, který vás přesměruje na poslední stránku, je nutné, aby stav zobrazení GridView byl povolen. (Pokud vaše stránkovací rozhraní neobsahuje přímý odkaz na poslední stránku, můžete stav zobrazení zakázat.)

Kliknutí na odkaz poslední stránky způsobí zpětné odeslání a dá GridView pokyn k aktualizaci jeho PageIndex vlastnosti. Pokud kliknete na odkaz poslední stránky, Objekt GridView přiřadí jeho PageIndex vlastnost k hodnotě o jednu menší, než je jeho PageCount vlastnost. Když je stav zobrazení zakázaný, PageCount hodnota se v rámci zpětného odeslání ztratí a PageIndex místo toho se přiřadí maximální celočíselná hodnota. Dále se Objekt GridView pokusí určit index počátečního řádku vynásobením PageSize vlastností a PageCount . Výsledkem je, OverflowException že produkt překračuje maximální povolenou celočíselnou velikost.

Implementace vlastního stránkování a řazení

Naše aktuální vlastní implementace stránkování vyžaduje, aby pořadí, podle kterého jsou data stránkována, bylo při vytváření GetProductsPaged uložené procedury zadáno staticky. Možná jste si však všimli, že inteligentní značka GridView obsahuje kromě možnosti Povolit stránkování také zaškrtávací políčko Povolit řazení. Přidání podpory řazení do objektu GridView s naší aktuální vlastní implementací stránkování bohužel seřadí pouze záznamy na aktuálně zobrazené stránce dat. Pokud například gridView nakonfigurujete tak, aby podporoval také stránkování, a pak při zobrazení první stránky dat seřadíte podle názvu produktu v sestupném pořadí, změní se pořadí produktů na stránce 1. Jak ukazuje obrázek 18, takové ukazuje Carnarvon Tigers jako první produkt při řazení v obráceném abecedním pořadí, což ignoruje 71 dalších produktů, které přicházejí po Carnarvon Tigers, abecedně; Při řazení jsou brány v úvahu pouze ty záznamy na první stránce.

Seřadí se jenom data zobrazená na aktuální stránce.

Obrázek 18: Seřadí se pouze data zobrazená na aktuální stránce (kliknutím zobrazíte obrázek v plné velikosti).

Řazení se vztahuje pouze na aktuální stránku dat, protože k řazení dochází po načtení dat z metody BLL s GetProductsPaged a tato metoda vrací pouze tyto záznamy pro konkrétní stránku. Aby bylo možné správně implementovat řazení, musíme předat výraz sort metodě GetProductsPaged , aby data bylo možné před vrácením konkrétní stránky dat správně seřadit. V dalším kurzu se dozvíme, jak toho dosáhnout.

Implementace vlastního stránkování a odstranění

Pokud povolíte funkci odstranění v objektu GridView, jehož data jsou stránkována pomocí vlastních technik stránkování, zjistíte, že při odstranění posledního záznamu z poslední stránky GridView zmizí místo toho, aby odpovídajícím způsobem zmenšoval GridView s PageIndex. Pokud chcete tuto chybu reprodukovat, povolte odstranění právě vytvořeného kurzu. Přejděte na poslední stránku (strana 9), kde byste měli vidět jeden produkt, protože jsme se stránkovat přes 81 produktů, 10 produktů najednou. Odstraňte tento produkt.

Po odstranění posledního produktu by gridView měl automaticky přejít na osmou stránku a tato funkce se zobrazí s výchozím stránkováním. S vlastním stránkováním však po odstranění posledního produktu na poslední stránce GridView jednoduše zmizí z obrazovky úplně. Přesný důvod , proč k tomu dochází, je trochu nad rámec tohoto kurzu; Podrobnosti o zdroji tohoto problému najdete v části Odstranění posledního záznamu na poslední stránce z objektu GridView s vlastním stránkováním . V souhrnu je příčinou následující posloupnost kroků, které jsou provedeny GridView při kliknutí na tlačítko Odstranit:

  1. Odstranění záznamu
  2. Získání odpovídajících záznamů, které se mají zobrazit pro zadané PageIndex a PageSize
  3. Zkontrolujte, jestli PageIndex hodnota nepřekračuje počet stránek dat ve zdroji dat. Pokud ano, automaticky se sníží vlastnost GridView s PageIndex .
  4. Vytvoření vazby příslušné stránky dat k objektu GridView pomocí záznamů získaných v kroku 2

Problém pramení ze skutečnosti, že v kroku 2 PageIndex se při načítání zobrazených záznamů stále PageIndex používá poslední stránka, jejíž jediný záznam byl právě odstraněn. Proto se v kroku 2 nevrátí žádné záznamy, protože poslední stránka dat už neobsahuje žádné záznamy. Potom v kroku 3 GridView zjistí, že jeho PageIndex vlastnost je větší než celkový počet stránek ve zdroji dat (protože jsme odstranili poslední záznam na poslední stránce), a proto sníží jeho PageIndex vlastnost. V kroku 4 GridView se pokusí vytvořit vazbu na data načtená v kroku 2; v kroku 2 však nebyly vráceny žádné záznamy, takže výsledkem je prázdný Objekt GridView. Při výchozím stránkování se tento problém neobjeví, protože v kroku 2 jsou všechny záznamy načteny ze zdroje dat.

K vyřešení tohoto problému máme dvě možnosti. Prvním je vytvoření obslužné rutiny události pro obslužnou rutinu události GridView, RowDeleted která určuje, kolik záznamů bylo zobrazeno na stránce, která byla právě odstraněna. Pokud by existoval pouze jeden záznam, pak právě odstraněný záznam musel být poslední a musíme dekrementovat GridView s PageIndex. Samozřejmě chceme aktualizovat PageIndex pouze v případě, že operace odstranění byla skutečně úspěšná, což se dá určit zajištěním, že e.Exception vlastnost je null.

Tento přístup funguje, protože aktualizuje PageIndex následující krok 1, ale před krokem 2. Proto se v kroku 2 vrátí příslušná sada záznamů. K tomu použijte následující kód:

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

Alternativním alternativním řešením je vytvořit obslužnou rutinu události objectDataSource a RowDeleted nastavit AffectedRows vlastnost na hodnotu 1. Po odstranění záznamu v kroku 1 (ale před opětovným načtením dat v kroku 2) GridView aktualizuje jeho PageIndex vlastnost, pokud operace ovlivnila jeden nebo více řádků. AffectedRows Vlastnost objectDataSource však není nastavena, a proto je tento krok vynechán. Jedním ze způsobů, jak tento krok provést, je nastavit vlastnost ručně AffectedRows , pokud se operace odstranění úspěšně dokončí. To lze provést pomocí kódu, jako je následující:

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

Kód pro obě tyto obslužné rutiny událostí najdete v příkladu EfficientPaging.aspx ve třídě kódu na pozadí.

Porovnání výkonu výchozího a vlastního stránkování

Vzhledem k tomu, že vlastní stránkování načítá pouze potřebné záznamy, zatímco výchozí stránkování vrací všechny záznamy pro každou zobrazenou stránku, je jasné, že vlastní stránkování je efektivnější než výchozí stránkování. O kolik efektivnější je ale vlastní stránkování? Jaký druh zvýšení výkonu lze dosáhnout přechodem z výchozího stránkování na vlastní stránkování?

Bohužel, neexistuje jedna velikost pro všechny odpovědi. Zvýšení výkonu závisí na několika faktorech. Mezi dva nejvýznamnější patří počet stránkovaných záznamů a zatížení databázového serveru a komunikační kanály mezi webovým serverem a databázovým serverem. U malých tabulek s několika desítkami záznamů může být rozdíl ve výkonu zanedbatelný. U velkých tabulek s tisíci a stovkami tisíc řádků je ale rozdíl ve výkonu akutní.

Můj článek "Vlastní stránkování v ASP.NET 2.0 s SQL Server 2005" obsahuje některé testy výkonnosti, které jsem provedl, abych ukázal rozdíly ve výkonu mezi těmito dvěma technikami stránkování při stránkování v databázové tabulce s 50 000 záznamy. V těchto testech jsem prozkoumal čas spuštění dotazu na úrovni SQL Server (pomocí SQL Profileru) a na stránce ASP.NET pomocí funkcí trasování ASP.NET s. Mějte na paměti, že tyto testy byly spuštěny na vývojovém poli s jedním aktivním uživatelem, a proto jsou nevědecké a nenapodobují typické vzorce zatížení webu. Bez ohledu na to výsledky ukazují relativní rozdíly v době provádění výchozího a vlastního stránkování při práci s dostatečně velkými objemy dat.

Prům. doba trvání (s) Čte
Výchozí stránkování SQL Profileru 1.411 383
Vlastní stránkování SQL Profileru 0.002 29
Výchozí trasování stránkování ASP.NET 2.379
Trasování vlastního stránkování ASP.NET 0.029

Jak vidíte, načtení konkrétní stránky dat vyžadovalo v průměru o 354 čtení méně a dokončení za zlomek času. Na ASP.NET stránce byla vlastní stránka schopna vykreslit téměř 1/100času , který trvalo při použití výchozího stránkování.

Souhrn

K implementaci výchozího stránkování stačí zaškrtnout políčko Povolit stránkování v inteligentní značce webového ovládacího prvku dat, ale taková jednoduchost je za cenu výkonu. Při výchozím stránkování platí, že když uživatel požádá o libovolnou stránku dat, vrátí se všechny záznamy, i když se může zobrazit jen malý zlomek z nich. Pro boj s touto režií na výkon nabízí ObjectDataSource alternativní možnost stránkování vlastní stránkování.

I když se vlastní stránkování zlepšuje při výchozích problémech s výkonem stránkování tím, že načítá pouze ty záznamy, které je potřeba zobrazit, je více zapojené implementovat vlastní stránkování. Nejprve je potřeba napsat dotaz, který správně (a efektivně) přistupuje ke konkrétní podmnožině požadovaných záznamů. Toho lze dosáhnout mnoha způsoby; V tomto kurzu jsme se zabývali použitím nové ROW_NUMBER() funkce SQL Server 2005 k seřaďte výsledky a pak vrátíte jenom ty výsledky, jejichž pořadí spadá do zadaného rozsahu. Kromě toho musíme přidat prostředky k určení celkového počtu stránkovaných záznamů. Po vytvoření těchto metod DAL a BLL musíme také nakonfigurovat ObjectDataSource tak, aby mohl určit celkový počet záznamů, které jsou stránkovány, a správně předat počáteční index řádku a maximální počet řádků hodnoty BLL.

I když implementace vlastního stránkování vyžaduje několik kroků a není tak jednoduchá jako výchozí stránkování, vlastní stránkování je při stránkování dostatečně velkých objemů dat nezbytné. Jak ukázaly zkoumané výsledky, vlastní stránkování může z doby vykreslování ASP.NET stránky krátit sekundy a může odlehčovat zatížení databázového serveru o jeden nebo více řádů.

Všechno nejlepší na programování!

O autorovi

Scott Mitchell, autor sedmi knih o ASP/ASP.NET a zakladatel 4GuysFromRolla.com, pracuje s webovými technologiemi Microsoftu od roku 1998. Scott pracuje jako nezávislý konzultant, školitel a spisovatel. Jeho nejnovější kniha je Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Můžete ho zastihnout na mitchell@4GuysFromRolla.comadrese . nebo prostřednictvím jeho blogu, který najdete na adrese http://ScottOnWriting.NET.