Autor Téma: FireDAC - Refresh  (Přečteno 729 krát)

Offline chaloup

  • Mladík
  • **
  • Příspěvků: 85
  • Karma: 9
    • Verze Delphi: Delphi 10.2
FireDAC - Refresh
« kdy: 11-01-2017, 11:41:59 »
zdar,
narazil jsem na zvláštní (teda podle mě je zvláštní) chování FireDAC ve spojení s Firebirdem (ostatní db jsem nezkoušel, je možný, že se to tak chová všude).
Refresh se chová rozdílně, když je vyplněno UpdateOptions.KeyFields (nebo nevyplněno).
Mám připojený DBGrid a když v KeyFields není nic vyplněno a zavolám Refresh, tak se znovu načtou pouze záznamy, které grid zobrazuje.
Když KeyFields vyplním a zavolám refresh provede se Refresh, ale načtou se úplně všechny záznamy, jako by se zavolalo ještě FetchAll.
Funguje to tak i když nastavím u nějakého fieldu, že je klíč - ProviderFlags := [pfInKey]

Testováno na Berlin Upd2

Offline chaloup

  • Mladík
  • **
  • Příspěvků: 85
  • Karma: 9
    • Verze Delphi: Delphi 10.2
Re:FireDAC - Refresh
« Odpověď #1 kdy: 16-10-2017, 18:38:17 »
Tak jsem se na ten problém zeptal podpory, podle nich je to by-design, mě se to chování nezdá správné. Jak píšou, na řádku 5141 se ten FetchAll opravdu volá, když je vyplněný index.
Citace
The behaviour that you describe looks to be as designed. By setting pfInKey in the provider flags, you are telling FireDAC that the table in the query has a primary key. If I look at line 5141 of FireDAC.Comp.DataSet.pas,  I see that the rows will be fetched if a primary key is defined:

if sKeyFields <> '' then begin
   CheckFetchedAll;

Online Delfin

  • Hrdina
  • ****
  • Příspěvků: 373
  • Karma: 16
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
    • Ibi Yoyo :)
Re:FireDAC - Refresh
« Odpověď #2 kdy: 16-10-2017, 23:51:33 »
O jake komponente se tu bavime (TFDQuery)? Muzu poprosit o jeji uplnou konfiguraci?
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 chaloup

  • Mladík
  • **
  • Příspěvků: 85
  • Karma: 9
    • Verze Delphi: Delphi 10.2
Re:FireDAC - Refresh
« Odpověď #3 kdy: 17-10-2017, 09:38:07 »
Jo jedná se o TFDQuery.  Když nastavím pfInKey:
Kód: [Vybrat]
FDQuery1.Fields.FieldByName('MY_ID').ProviderFlags := [pfInWhere, pfInUpdate, pfInKey]; nebo v update options nastav KeyFields.
Tak refresh začne dělat FetchAll.
Protože v FireDAC.Comp.DataSet.pas na řádku 5141 je:
Kód: [Vybrat]
if sKeyFields <> '' then begin
   CheckFetchedAll;

Online Delfin

  • Hrdina
  • ****
  • Příspěvků: 373
  • Karma: 16
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
    • Ibi Yoyo :)
Re:FireDAC - Refresh
« Odpověď #4 kdy: 08-11-2017, 05:26:30 »
Ano, tak tomu je. Metoda si zapamatuje hodnotu klice, vycisti storage, pak prenese vsechny zaznamy a snazi se lokalizovat zaznam s ulozenou hodnotou klice.

Myslim si tedy ze FireDAC jen nechce ztratit existujici pozici kurzoru a v ramci "jednoduchosti" prenese vsechny zaznamy. Se zmenou parametru muze totiz objekt prenest jiny resultset, predtim zamereny zaznam uz nemusi existovat, nebo muze byt na jine pozici. Lze tam i vycist, ze pokud neni v zaznamu klic (lRecIndSet == False), pak se nastavuje kurzor podle taktez ulozeneho RecNo.

Pokud tomu tak je, bylo by rozumnejsi kdyby se mu podarilo obnovit jen zaznam s kurzorem a prenesl packety do velikosti poloviny RowsetSize nahoru a dolu (pripadne patricnym pomerem nahoru a dolu). Co je nejspis problem je jak po uprave bindovanych parametru prikazu ziskat specificky packet zaznamu kde se nachazi ten s ulozenou hodnotou klice (ten puvodne zamereny). Zkusim se podivat na moznosti, byt tomu moc sanci nedavam...
« Poslední změna: 08-11-2017, 05:47:02 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é!

Online Delfin

  • Hrdina
  • ****
  • Příspěvků: 373
  • Karma: 16
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
    • Ibi Yoyo :)
Re:FireDAC - Refresh
« Odpověď #5 kdy: 08-11-2017, 06:10:07 »
Zkusim se podivat na moznosti, byt tomu moc sanci nedavam...

Chovanim metodu podobnou Resync s reflexi zmen hodnot bindovanych parametru.
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é!

Online Delfin

  • Hrdina
  • ****
  • Příspěvků: 373
  • Karma: 16
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
    • Ibi Yoyo :)
Re:FireDAC - Refresh
« Odpověď #6 kdy: 08-11-2017, 07:02:09 »
Zkusim se podivat na moznosti, byt tomu moc sanci nedavam...

A sance (alespon v soucasnosti) nejsou. FireDAC nedokaze prenest z DBMS specificky packet zaznamu obsahujici urcity zaznam (i kdyby to DBMS podporoval, takova implementace neexistuje). Je vsak zbytecnost pri fmOnDemand prenaset vsechny zaznamy jen pro zachovani zamereneho kurzoru. Porad by slo (treba i na zaklade nastaveni nejake nove property ve smyslu ForgetCursorAtRefresh) tahat packety zaznamu dokud se neobjevi ten puvodne zamereny, dotahnout packety do velikosti RowsetSize a smycku ukoncit nebo zamereni zapomenout a prenest jen RowsetSize pocet zaznamu.
« Poslední změna: 08-11-2017, 07:12:38 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 chaloup

  • Mladík
  • **
  • Příspěvků: 85
  • Karma: 9
    • Verze Delphi: Delphi 10.2
Re:FireDAC - Refresh
« Odpověď #7 kdy: 08-11-2017, 08:51:44 »
Řešil jsem to s technickou podporou, výsledek 0, je to tak v kódu, tak to MUSÍ být dobře, o tom, že je to nesmysl odmítli diskutovat.
- nikde není popsáno v dokumentaci, že přidání primárního klíče mění způsob jakým se dělá refresh
- žádný jiný knihovny to nedělaj (co jsem zkoušel)
- když jsem ten Refresh přepsal a to CheckFetchedAll jsem vyhodil, tak všechno funguje, načte to pouze tolik záznamů aby to našlo předchozí pozici

V příloze je patch, kterej to opraví, funguje mi to v 10.2.

Online Delfin

  • Hrdina
  • ****
  • Příspěvků: 373
  • Karma: 16
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
    • Ibi Yoyo :)
Re:FireDAC - Refresh
« Odpověď #8 kdy: 08-11-2017, 09:10:13 »
- když jsem ten Refresh přepsal a to CheckFetchedAll jsem vyhodil, tak všechno funguje, načte to pouze tolik záznamů aby to našlo předchozí pozici

Tomu popravde neverim (muzu overit) :) Interni storage se vyprazdnuje (Table.Clear) a LocateRecord prave s tim storage pracuje (FSourceView.Search). Musi se do nej ale znova prenest zaznamy z DBMS. Jen namisto prenosu vsech si v pripade "on demand" rezimu vyrob smycku a tahej packety dokud nenajdes zaznam shodujici se s ulozenym klicem, pak ze smycky vyskoc. Nevim o moznosti kdy by to za tebe delal ten storage. Nicmene i tak se muze stat ze se prenese zbytecne moc zaznamu (posledne vybrany zaznam uz nemusi v obnovenem resultsetu existovat). A to vse jen za cenu pozice kurzoru.
« Poslední změna: 08-11-2017, 09:12:52 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 Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 2976
  • Karma: 29
    • Verze Delphi: XE7 professional
Re:FireDAC - Refresh
« Odpověď #9 kdy: 08-11-2017, 09:41:35 »
Citace
nikde není popsáno v dokumentaci, že přidání primárního klíče mění způsob jakým se dělá refresh
Ja som na to narazil ;)
Citace
A to vse jen za cenu pozice kurzoru.
Ja ho beztak chcem mať na prvej/poslednej pozícii :)
Delphi XE7, FireBird
Expert na kladenie nejasne formulovaných otázok.

Offline chaloup

  • Mladík
  • **
  • Příspěvků: 85
  • Karma: 9
    • Verze Delphi: Delphi 10.2
Re:FireDAC - Refresh
« Odpověď #10 kdy: 08-11-2017, 10:15:09 »
Tomu popravde neverim (muzu overit) :)
Já jsem nezkoumal kód, ale udělal jsem si demo s tabulkou, která má 10.000 záznamů zobrazených v gridu. Když jsem přesunul pozici v gridu na patřičný počet záznamů a dal refresh, tak se to chovalo dobře.
Když jsem udělal pozici na konec (načetlo se všechno) a potom jsem skočil někam doprostřed a udělal refresh, tak se načetlo jen tolik záznamů od začátku tabulky aby se našel záznam, který má pozici. Co bylo nad už se nenačetlo i když před refresh to načtené bylo.

Online Delfin

  • Hrdina
  • ****
  • Příspěvků: 373
  • Karma: 16
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
    • Ibi Yoyo :)
Re:FireDAC - Refresh
« Odpověď #11 kdy: 08-11-2017, 10:24:50 »
Ja ho beztak chcem mať na prvej/poslednej pozícii :)

Pro tvuj pripad je to vyhodne, protoze chces syejne vzdy tahat vsechny zaznamy :) I tak se ale bude FireDAC snazit nastavit kurzor tam kde byl. Problem je kdyz mas "on demand" rezim a provedes neco takoveho:

Kód: Delphi [Vybrat]
  1. FDQuery.SQL.Text := 'SELECT ID, MyField FROM MyTable WHERE MyField BETWEEN :LowValue AND :HighValue';
  2. FDQuery.ParamByName('LowValue').AsInteger := 1;
  3. FDQuery.ParamByName('HighValue').AsInteger := 10;
  4. FDQuery.Open;
  5.  
  6. FDQuery.ParamByName('LowValue').AsInteger := 11;
  7. FDQuery.ParamByName('HighValue').AsInteger := 500000;
  8. FDQuery.Refresh; // ← tady se prenesou vsechny zaznamy pri hledani posledne vybraneho (v resultsetu v tomto pripade nebude)

S vyse uvedenym refreshem si nelze poradit jinak nez prenest vsechny zaznamy (i kdyz to bude davkove). Nebo se na zachovani puvodni pozice kurzoru vykaslat. Proto bych byl pro novou volbu nastaveni. Pri jejim vypnuti by sis mohl zaznam sam lokalizovat (protoze vis jak jsi upravil bindovane parametry a tim padem mas sanci odhadnout zda muze drive vybrany zaznam existovat v nove prenasenem resultsetu).
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é!

Online Delfin

  • Hrdina
  • ****
  • Příspěvků: 373
  • Karma: 16
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
    • Ibi Yoyo :)
Re:FireDAC - Refresh
« Odpověď #12 kdy: 08-11-2017, 10:31:13 »
Když jsem udělal pozici na konec (načetlo se všechno) a potom jsem skočil někam doprostřed a udělal refresh, tak se načetlo jen tolik záznamů od začátku tabulky aby se našel záznam, který má pozici. Co bylo nad už se nenačetlo i když před refresh to načtené bylo.

To zni spis jakoby se o to nacteni dat postaral sam grid (resp. jeho skrolovani). Zkus zrusit propojeni s gridem a pote co zavolas svuj modifikovany refresh zkus overit kolik je zaznamu ve storage (tj. kolik zaznamu se po jeho vycisteni na klienta skutecne preneslo):

Kód: Delphi [Vybrat]
  1. FDQuery.Refresh;
  2. FDQuery.Table.Rows.Count; // ← tipuju 0
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 chaloup

  • Mladík
  • **
  • Příspěvků: 85
  • Karma: 9
    • Verze Delphi: Delphi 10.2
Re:FireDAC - Refresh
« Odpověď #13 kdy: 08-11-2017, 10:49:47 »
Funguje to i bez připojenýho gridu.
Kód: [Vybrat]
  FDQuery1.Refresh;
  Memo1.Lines.Add(IntToStr(FDQuery1.RecordCount));
  Memo1.Lines.Add(IntToStr(FDQuery1.Table.Rows.Count));
  Memo1.Lines.Add(IntToStr(FDQuery1.RecNo));
Když stojím na prvním záznamu, výsledek je:
50
50
1
na posledním:
10001
10001
10001

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 2976
  • Karma: 29
    • Verze Delphi: XE7 professional
Re:FireDAC - Refresh
« Odpověď #14 kdy: 08-11-2017, 10:51:00 »
Citace
S vyse uvedenym refreshem si nelze poradit jinak nez prenest vsechny zaznamy (i kdyz to bude davkove). Nebo se na zachovani puvodni pozice kurzoru vykaslat.
Ja tú pôvodnú pozíciu naozaj nepotrebujem. Keď pracujem s tabuľkami (vo VST), tak používam Locate(). Pri SELECT
  • buď prechádzam celý dataset
  • alebo ho celý načítam do VST a zahadzujem ho (Close)
Citace
Proto bych byl pro novou volbu nastaveni. Pri jejim vypnuti by sis mohl zaznam sam lokalizovat
To si musím znova pozrieť čo má na čo vplyv.
Citace
(protoze vis jak jsi upravil bindovane parametry a tim padem mas sanci odhadnout zda muze drive vybrany zaznam existovat v nove prenasenem resultsetu).
Buď viem, že tam nebude, alebo nemám šancu to odhadnúť. Lebo to záleží na štruktúre údajov užívateľa.
Delphi XE7, FireBird
Expert na kladenie nejasne formulovaných otázok.

 

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: