Autor Téma: TFDTable + Stránkování  (Přečteno 649 krát)

Offline xnukes

  • Mladík
  • **
  • Příspěvků: 62
  • Karma: 1
    • Verze Delphi: XE7
    • Bludspeed s.r.o.
TFDTable + Stránkování
« kdy: 04-08-2017, 10:10:00 »
Ahojte,

potřeboval bych malinko poradit. Naprogramoval jsem si vlastní stránkovač a potřeboval bych dostat nastavení limitu do TFDTable.

Resp. vytvořit object TFDTable, nastavím mu connection, tablename, indexfieldnames a otevru ji.

pak nastavim maximalni pocet radku na stránku TableList.FetchOptions.RowsetSize = 25;

ale nevím kde mám nastavit v jaké property od kterýho záznamu má začít. Může mi někdo helfnout ?

Děkuji

Offline Radek Červinka

  • Administrátoři
  • Padawan
  • *****
  • Příspěvků: 1765
  • Karma: 72
    • Verze Delphi: D5,D2007, DXE, DXE2 + 2 poslední (Tokyo)
    • O Delphi v češtině
Re:TFDTable + Stránkování
« Odpověď #1 kdy: 04-08-2017, 10:42:52 »
Zkus nastavit RecNo
Embarcadero MVP - Czech republic

Offline xnukes

  • Mladík
  • **
  • Příspěvků: 62
  • Karma: 1
    • Verze Delphi: XE7
    • Bludspeed s.r.o.
Re:TFDTable + Stránkování
« Odpověď #2 kdy: 04-08-2017, 10:45:57 »
Ahoj , díky zkusím, zkusil jsem i FetchOptions.RecsSkip := Offset; ale mám furt problém že mi FireDac vyhazuje error že mam duplicitní položky na unikatním indexu ze schématu databáze. Přitom databázově mám vše v pořádku.

Object vytvářím takto:
Kód: [Vybrat]
  TablePhmList := TFDTable.Create(Self);
  TablePhmList.Connection := DatabaseModule.FDConnection;
  TablePhmList.TableName := 'p_list_phm';
  TablePhmList.IndexFieldNames := 'phm_id';
  TablePhmList.FetchOptions.RowsetSize := Paginator.ItemsPerPage;
  TablePhmList.FetchOptions.RecordCountMode := cmTotal;
  TablePhmList.FormatOptions.SortLocale := LOCALE_USER_DEFAULT;
  TablePhmList.FetchOptions.RecsSkip := Paginator.OffsetStart;
  TablePhmList.Open();

Offline xnukes

  • Mladík
  • **
  • Příspěvků: 62
  • Karma: 1
    • Verze Delphi: XE7
    • Bludspeed s.r.o.
Re:TFDTable + Stránkování
« Odpověď #3 kdy: 04-08-2017, 11:09:19 »
Tak už jsem přišel na ten problém, stačilo nastavit SortOptions pouze na Primary-

Kód: [Vybrat]
TablePhmList.FormatOptions.SortOptions := [soPrimary];

Offline Delfin

  • Hrdina
  • ****
  • Příspěvků: 376
  • Karma: 16
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
    • Ibi Yoyo :)
Re:TFDTable + Stránkování
« Odpověď #4 kdy: 04-08-2017, 12:12:08 »
Co to znamena vlastni strankovac? Ptam se protoze live mode uz existuje...
A co chudinky ovce? Koupíš jim snad plovací vesty? Nebo jim nasadíš chůdy? Ještě lepší, kdybys je zkřížil s delfíny na ovce hopkavé!

Offline xnukes

  • Mladík
  • **
  • Příspěvků: 62
  • Karma: 1
    • Verze Delphi: XE7
    • Bludspeed s.r.o.
Re:TFDTable + Stránkování
« Odpověď #5 kdy: 04-08-2017, 13:00:36 »
no ja nemam rad ten live , chtel sem si napsat svuj jednoduchej, tzv 2x btn + combobox pro vyber stranky a tlacitka na predchozi nebo dalsi stranku, napr listujes 25 zaznamu na jednu stranku az do konce.

Offline xnukes

  • Mladík
  • **
  • Příspěvků: 62
  • Karma: 1
    • Verze Delphi: XE7
    • Bludspeed s.r.o.
Re:TFDTable + Stránkování
« Odpověď #6 kdy: 07-08-2017, 14:57:28 »
mohu se vas jeste optat dale ?

mam problem s tim ze mi nejde nastavit pocet zaznamu na stranku.

pri zmene ve strankovaci zasilam objekt TFDTable do procedury ktera nastavi RecNo podle strankovace coz funguje ale pri nastaveni FetchOptions.RowsetSize mi to ignoruje a vzdy vypise vsechny vysledky do konce datasetu. zkousel jsem i FetchOptions.RowsetSize ale s nicim jsem nepochodil.

popisu strucne od zacatku: formcreate -> vytvorim private TableList: TFDTable ... a zavolam Open(); ... pote se posle objekt TableList do procedury spolecne s paginatorem a ten uz by mel nastavit zacatek ukazatele + maximalni pocet radku na stranku.

ukazka:
Kód: [Vybrat]
  // procedure TableToStringGrid(...)
  Table.FetchOptions.RowsetSize := Paginator.ItemsPerPage;
  Table.RecNo := Paginator.OffsetStart;
  Table.FetchAgain;

  // add rows
  while not Table.Eof do
  begin
    Grid.Cells[0,ROW] := Table.FieldByName(FirstIndex).AsString;
    for I := Low(Fields.Fields) to High(Fields.Fields) do
    begin
      if Fields.Fields[I].ColType = 'string' then
      begin
        Grid.Cells[I+1,ROW] := Table.FieldByName(Fields.Fields[I].FieldName).AsString;
      end;
    end;
    ROW := ROW+1;
    Table.Next;
  end;

pokazde vypise radky od zadanyho RecNo ale pocet max radku neni tak jak mam zadany :(

Offline Radek Červinka

  • Administrátoři
  • Padawan
  • *****
  • Příspěvků: 1765
  • Karma: 72
    • Verze Delphi: D5,D2007, DXE, DXE2 + 2 poslední (Tokyo)
    • O Delphi v češtině
Re:TFDTable + Stránkování
« Odpověď #7 kdy: 07-08-2017, 15:06:14 »
Není to nahodou tím, že Table.FetchOptions.RowsetSize není to co si myslíš http://docwiki.embarcadero.com/Libraries/Tokyo/en/FireDAC.Stan.Option.TFDFetchOptions.RowsetSize, nýbrž dávka po které to bude načítat v případě FetchMode = fmOnDemand.

Takže když uděláš while not ds.EOF, tak on bude postupně dočítat data po těch dávkách dokud nebude EOF. Nahraď to not EOF max. počtem záznamů pro stránku, tj. not OEF and  ROW < Paginator.ItemsPerPage . nebo tak nějak
Embarcadero MVP - Czech republic

Offline Delfin

  • Hrdina
  • ****
  • Příspěvků: 376
  • Karma: 16
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
    • Ibi Yoyo :)
Re:TFDTable + Stránkování
« Odpověď #8 kdy: 07-08-2017, 15:08:16 »
Ty ten FireDAC trapis ;D

Citace
To change RowsetSize for an already used dataset, an application can call the Disconnect method first.

Zdroj

A popravde bych se nedivil formulaci "must call", protoze FireDAC uz muze mit v cache neco dotazene. FetchAgain dela neco jineho nez zni. Stejne jako RowsetSize, bohuzel. Nevim, asi bych zacal tak nejak od znova. Osobne bych asi pouzil spis query objekt a dotaz nad indexem.
« Poslední změna: 07-08-2017, 15:14:30 od Delfin »
A co chudinky ovce? Koupíš jim snad plovací vesty? Nebo jim nasadíš chůdy? Ještě lepší, kdybys je zkřížil s delfíny na ovce hopkavé!

Offline xnukes

  • Mladík
  • **
  • Příspěvků: 62
  • Karma: 1
    • Verze Delphi: XE7
    • Bludspeed s.r.o.
Re:TFDTable + Stránkování
« Odpověď #9 kdy: 07-08-2017, 15:15:03 »
upravil sem teda cyklus na : while not (Table.Eof) and (ROW <= Paginator.ItemsPerPage) do

coz se zda ze funguje. btw ja zkousel i fetchoptions RecsSkip a RecsMax s ruznyma modama ale taky mi to neslo i kdyz jsem zkusil disconnect , nastavit stranky a pak open. ale bez vysledku.

Delfinku: jojo dávám mu na prdel :D ne snažím se ho pořádně pochopit. s tím že tam pisou ze se musi odpojit to jsem se taky docetl ale nefakalo to :)

Offline Delfin

  • Hrdina
  • ****
  • Příspěvků: 376
  • Karma: 16
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
    • Ibi Yoyo :)
Re:TFDTable + Stránkování
« Odpověď #10 kdy: 12-08-2017, 08:08:02 »
1. TFDTable strankovac

Ja myslel spis na takovy kod (to je de-facto implementace strankovace; s kazdou zmenou offset nebo poctu radku je treba zavolat Disconnect, nastavit potrebne a dataset znovu otevrit):

Kód: Delphi [Vybrat]
  1. FDTable.Disconnect;
  2. FDTable.FetchOptions.RecsSkip := 10; // offset
  3. FDTable.FetchOptions.RecsMax := 100; // maximalni pocet radku
  4. FDTable.Open;

To je ale neefektivni protoze se interne pripravuje SQL prikaz pro kazdou zmenu stranky. Rekl bych ze to jde i efektivneji vzhledem k tomu, ze ma vetsina DBMS parametrizovatelnou LIMIT, OFFSET klauzuli (viz sekce 3). Pro posun pouze vpred (cili neco jineho nez je zadani, tedy jen pro zajimavost) se da pouzit nasledujici.

2. Posun pouze vpred o definovany pocet zaznamu

Pro postupne dotahovani zaznamu o definovany maximalni pocet se da pouzit nasledujici (tohle se neda pouzit pro strankovac ze zadani):

Kód: Delphi [Vybrat]
  1. var
  2.   Fetched: Integer;
  3. begin
  4.   FDTable.FetchOptions.Mode := fmManual; // manualni fetch zaznamu
  5.   FDTable.FetchOptions.RowsetSize := 100; // maximalni pocet radku
  6.   FDTable.Open;
  7.  
  8.   Fetched := FDTable.GetNextPacket; // pripadne FetchNext volat opakovane dokud nevrati hodnotu mensi nez RowsetSize (tj. posledni stranka)
  9.   if Fetched < FDTable.FetchOptions.RowsetSize then
  10.     NoMoreRecordsCanBeFetched;
  11. end;

3. Vlastni implementace strankovace

Protoze FireDAC zatim nechce umet parametrizovane LIMIT, OFFSET klauzule vyspelejsich DBMS, pokusim se sem utrousit jen vysvetleni s ukazkou prikazu pro par DBMS:

Kód: Delphi [Vybrat]
  1. SQLite     - SELECT Field1, Field2 FROM MyTable ORDER BY Field1 LIMIT :Limit OFFSET :Offset
  2. Firebird   - SELECT Field1, Field2 FROM MyTable ORDER BY Field1 ROWS :Offset + 1 TO :Offset + :Limit
  3. PostgreSQL - SELECT Field1, Field2 FROM MyTable ORDER BY Field1 LIMIT :Limit OFFSET :Offset
  4. SQL Server - SELECT Field1, Field2 FROM MyTable ORDER BY Field1 OFFSET :Offset ROWS FETCH NEXT :Limit ROWS ONLY

Prikaz se pripravi otevrenim v objektu TFDQuery. Pak se jen meni parametry Limit a Offset a vola metoda Refresh. To usetri opakovanou pripravu prikazu ktera je k videni v pripade sekce 1. P.S. klauzule ORDER BY pouzita byt musi, protoze DBMS negarantuji v jakem poradi vrati zaznamy pokud neni ORDER BY explicitne specifikovan.
« Poslední změna: 12-08-2017, 08:14:08 od Delfin »
A co chudinky ovce? Koupíš jim snad plovací vesty? Nebo jim nasadíš chůdy? Ještě lepší, kdybys je zkřížil s delfíny na ovce hopkavé!

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 1853
  • Karma: 87
    • Verze Delphi: D2007, XE3, DX10
Re:TFDTable + Stránkování
« Odpověď #11 kdy: 12-08-2017, 09:22:48 »
To je ale neefektivni protoze se interne pripravuje SQL prikaz pro kazdou zmenu stranky. Rekl bych ze to jde i efektivneji vzhledem k tomu, ze ma vetsina DBMS parametrizovatelnou LIMIT, OFFSET
No s ohledem, ze ten paginator obsluhuje clovek a i pro operatora jaderneho bloku se brala za uspokojivou odezva do 200 ms, tak bych to neresil. Konec koncu, treba na webu si taky sahas pro stranku znovu a nikdo se tim nezabyva.

Offline Delfin

  • Hrdina
  • ****
  • Příspěvků: 376
  • Karma: 16
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
    • Ibi Yoyo :)
Re:TFDTable + Stránkování
« Odpověď #12 kdy: 12-08-2017, 10:39:20 »
To je ale neefektivni protoze se interne pripravuje SQL prikaz pro kazdou zmenu stranky. Rekl bych ze to jde i efektivneji vzhledem k tomu, ze ma vetsina DBMS parametrizovatelnou LIMIT, OFFSET
No s ohledem, ze ten paginator obsluhuje clovek a i pro operatora jaderneho bloku se brala za uspokojivou odezva do 200 ms, tak bych to neresil. Konec koncu, treba na webu si taky sahas pro stranku znovu a nikdo se tim nezabyva.

Pravda. Docela by me i zajimalo, jestli je nektery DBMS natolik chytry, ze se "nauci" pri pouzivani stejnych dotazu (jen zmenach hodnot LIMIT a OFFSET) dotaz znovu nepripravovat ale jen naparsovat a interne dosadit parametry. Implementacne by to nemuselo byt zas tak slozite. Uvnitr server vidi dotaz rozlozeny (ma pro nej plan), takze by se mohl podivat do nejake cache kde ho mel pripraveny a dosadit jen pozmenene hodnoty. Verim ze uz neco takoveho u tech vyspelych existuje.

Ale je to skoda. FireDAC je k tomu pomerne blizko. Jednoduse dokaze takovy dotaz vygenerovat. Jen ne s parametry :'(:

Kód: Delphi [Vybrat]
  1. var
  2.   Generator: IADPhysCommandGenerator;
  3. begin
  4.   FDConnection.ConnectionIntf.CreateCommandGenerator(Generator, nil);
  5.   // hodnota 1 je offset, 100 je limit
  6.   ShowMessage(Generator.GenerateLimitSelect('SELECT MyField FROM MyTable ORDER BY Data WHERE MyField > 10', 1, 100));
  7. end;
« Poslední změna: 12-08-2017, 10:40:51 od Delfin »
A co chudinky ovce? Koupíš jim snad plovací vesty? Nebo jim nasadíš chůdy? Ještě lepší, kdybys je zkřížil s delfíny na ovce hopkavé!

Offline Delfin

  • Hrdina
  • ****
  • Příspěvků: 376
  • Karma: 16
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
    • Ibi Yoyo :)
Re:TFDTable + Stránkování
« Odpověď #13 kdy: 12-08-2017, 12:55:55 »
Docela by me i zajimalo, jestli je nektery DBMS natolik chytry, ze se "nauci" pri pouzivani stejnych dotazu (jen zmenach hodnot LIMIT a OFFSET) dotaz znovu nepripravovat ale jen naparsovat a interne dosadit parametry.

Abych znel presneji, myslim tim pri uvolneni prikazu a jeho opetovnem otevreni (jen s jinymi hodnotami, ne s bindovanymi parametry). Tedy zda umi nektery DBMS zpracovat "podobny" prikaz (de-facto stejny, jen jine hodnoty) efektivneji nez jen opakovanou pripravou naprosto stejneho planu.

Oprava:

Kód: Delphi [Vybrat]
  1. var
  2.   Generator: IFDPhysCommandGenerator;
  3. begin
  4.   FDConnection.ConnectionIntf.CreateCommandGenerator(Generator, nil);
  5.   // hodnota 1 je offset, 100 je limit
  6.   ShowMessage(Generator.GenerateLimitSelect('SELECT MyField FROM MyTable ORDER BY Data WHERE MyField > 10', 1, 100));
  7. end;
« Poslední změna: 12-08-2017, 13:17:20 od Delfin »
A co chudinky ovce? Koupíš jim snad plovací vesty? Nebo jim nasadíš chůdy? Ještě lepší, kdybys je zkřížil s delfíny na ovce hopkavé!

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 1853
  • Karma: 87
    • Verze Delphi: D2007, XE3, DX10
Re:TFDTable + Stránkování
« Odpověď #14 kdy: 12-08-2017, 13:33:00 »
Abych znel presneji, myslim tim pri uvolneni prikazu a jeho opetovnem otevreni (jen s jinymi hodnotami, ne s bindovanymi parametry). Tedy zda umi nektery DBMS zpracovat "podobny" prikaz (de-facto stejny, jen jine hodnoty) efektivneji nez jen opakovanou pripravou naprosto stejneho planu.
Podle me to funguje v ramci transakce: kdyz poslu parametrizovany SQL, tak si ho server rozparsuej, optimalizuje a ulozi a zrejme vrati nejake jeho handle. No a vsechny nasledujici dotazy uz posilaji jinym protokolem jen seznam parametru. A IMHO jakmile ukoncis transakci, tak to server zahodi, protoze jeho zivot se odehrava v podstate jenom v transakcich. Jina vec je, ze normalni je nechavat si zivou jednu RO transakci, at uz to udela infrastruktura za programatora nebo si to programator sam osefuje. Ale pak bude zalezet na to widgetu na strane klienta, jesti se dokazu dostat k tomu internimu handlu dotazu a dokaze pracovat tak, aby neposilal SQL text, ale rovnou handle+parametry. Vetsina datasetu asi ne.

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 2976
  • Karma: 29
    • Verze Delphi: XE7 professional
Re:TFDTable + Stránkování
« Odpověď #15 kdy: 12-08-2017, 14:09:40 »
Asi to má súvis.
Ak chcem v TFDQuery zmeniť parametre, tak ho musím zavrieť, nastaviť parametre a potom ho znova otvoriť. Ja som inú možnosť nenašiel. Ale ja som v tom slabý.

Ja ako laik by som danú úlohu riešil tak, že by som natiahol všetky záznamy a podľa potreby načítaval sadu záznamov pomocou zmeny kurzora.
Tak ako to tu rozoberáte, mi to vôbec nejde do hlavy ;)
Delphi XE7, FireBird
Expert na kladenie nejasne formulovaných otázok.

Offline Delfin

  • Hrdina
  • ****
  • Příspěvků: 376
  • Karma: 16
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
    • Ibi Yoyo :)
Re:TFDTable + Stránkování
« Odpověď #16 kdy: 12-08-2017, 15:12:53 »
Asi to má súvis.
Ak chcem v TFDQuery zmeniť parametre, tak ho musím zavrieť, nastaviť parametre a potom ho znova otvoriť. Ja som inú možnosť nenašiel

To prave neni uplne efektivni. Funguje to tak ze se dotaz otevre, a pak se meni jen parametry a vola metoda Refresh. Tim volanim Refresh se pak posilaji jen hodnoty parametru (DBMS nemusi znovu kompilovat stejny dotaz). Zavrenim a otervenim se prave dotaz na strane DBMS nejspis vzdy znovu kompiluje, pokud tedy neni DBMS natolik inteligentni a vsimne si opakovaneho volani dotazu ktery po kompilaci vypada naprosto stejne (ma stejny execution plan), jen s jinymi hodnotami (o cemz se tu ted bavime).

Kód: Delphi [Vybrat]
  1. FDQuery.SQL.Text := 'SELECT Field1 FROM MyTable WHERE Field2 > :MyValue';
  2. FDQuery.ParamByName('MyValue').AsInteger := 666;
  3. FDQuery.Open;
  4.  
  5. FDQuery.ParamByName('MyValue').AsInteger := 667;
  6. FDQuery.Refresh;
« Poslední změna: 12-08-2017, 15:25:36 od Delfin »
A co chudinky ovce? Koupíš jim snad plovací vesty? Nebo jim nasadíš chůdy? Ještě lepší, kdybys je zkřížil s delfíny na ovce hopkavé!

Offline Delfin

  • Hrdina
  • ****
  • Příspěvků: 376
  • Karma: 16
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
    • Ibi Yoyo :)
Re:TFDTable + Stránkování
« Odpověď #17 kdy: 12-08-2017, 16:38:10 »
kdyz poslu parametrizovany SQL, tak si ho server rozparsuej, optimalizuje a ulozi a zrejme vrati nejake jeho handle. No a vsechny nasledujici dotazy uz posilaji jinym protokolem jen seznam parametru.

Je tomu tak. Jinak zbezne jsem se dival kolem a zda se ze nektere servery si vyrabi i "offline" cache pro (parametrizovane) dotazy (vyrobi hash dotazu a ulozi si jej spolu s planem). Nikde jsem ale nenasel zminku o porovnani planu (tj. pokud se najde stejny plan, pouzije se jeho cache dat, pokud je to mozne). Napr. pro tyto 2 dotazy:

Kód: MySQL [Vybrat]
  1. SELECT MyField FROM MyTable WHERE SomeField BETWEEN 100 AND 500 ORDER BY MyField
  2. SELECT MyField FROM MyTable WHERE SomeField BETWEEN 200 AND 400 ORDER BY MyField

asi DBMS nepujde az tak daleko ze by porovnal plany a sahl pro data z cache prvniho dotazu.
« Poslední změna: 12-08-2017, 16:57:25 od Delfin »
A co chudinky ovce? Koupíš jim snad plovací vesty? Nebo jim nasadíš chůdy? Ještě lepší, kdybys je zkřížil s delfíny na ovce hopkavé!

 

S rychlou odpovědí můžete používat BB kódy a emotikony jako v běžném okně pro odpověď, ale daleko rychleji.

Jméno: E-mail:
Ověření:
Křestní jméno zpěváka Gotta: