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

Offline Delfin

  • Hrdina
  • ****
  • Příspěvků: 362
  • Karma: 15
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
    • Ibi Yoyo :)
Re:FireDAC - Refresh
« Odpověď #15 kdy: 08-11-2017, 11:27:01 »
Funguje to i bez připojenýho gridu.

A jo. Uz tomu chapu. Tys de-facto odrovnal cely blok hledani podle hodnoty klice. To muzes sundat rovnou cely ten blok (protoze efektivne nebude nic delat) a lokalizovat rovnou pomoci RecNo (cimz muzes kurzorem odskocit na jiny zaznam nez byl predtim vybrany):

Kód: Delphi [Vybrat]
  1.   lRecIndSet := False;
  2.   if sKeyFields <> '' then begin
  3.     CheckFetchedAll; // ← preskocenim prenosu radku nemuze LocateRecord nikdy vratit True (protoze je storage prazdny)
  4.     if LocateRecord(sKeyFields, vLastKeyValue, [], iNewRecNo) then begin
  5.       FRecordIndex := iNewRecNo;
  6.       lRecIndSet := True; // ← sem se nikdy nedostanes
  7.     end;
  8.   end;
  9.   if not lRecIndSet then // ← a tim padem se ti kurzor lokalizuje pomoci ulozeneho RecNo (prenos zaznamu je tady resen efektivneji)
  10.     InternalSetRecNo(iLastRecNo);
« Poslední změna: 08-11-2017, 11:54:15 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ů: 362
  • Karma: 15
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
    • Ibi Yoyo :)
Re:FireDAC - Refresh
« Odpověď #16 kdy: 08-11-2017, 11:38:13 »
Ja tú pôvodnú pozíciu naozaj nepotrebujem. Keď pracujem s tabuľkami (vo VST), tak používam Locate().

Soucasna implementace FireDAC (Tokyo) se bude o lokalizaci snazit pokazde. Bud klicem (neefektivne prenosem vsech zaznamu) nebo RecNo (cimz muzes skoncit na jinem zaznamu nez byl predtim vybrany). Prave proto bych byl pro novou volbu nastaveni (neco jako ForgetCursorAtRefresh a rucni lokaci, pokud o ni mas zajem).
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ů: 2971
  • Karma: 29
    • Verze Delphi: XE7 professional
Re:FireDAC - Refresh
« Odpověď #17 kdy: 08-11-2017, 13:10:03 »
Keďže to ušetrí prostriedky a čas, tak záujem mám. Tak ako aj o MVC ;)
Tá lokalizácia pomocou ID sa dá potlačiť nastavením nejakých vlastností. Len si nepamätám ktorých a ako. Tu je k tomu nejaký pokec http://docs.embarcadero.com/products/rad_studio/firedac/frames.html To je základná strana. Viď prílohu.
« Poslední změna: 08-11-2017, 13:12:57 od Stanislav Hruška »
Delphi XE7, FireBird
Expert na kladenie nejasne formulovaných otázok.

Offline Delfin

  • Hrdina
  • ****
  • Příspěvků: 362
  • Karma: 15
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
    • Ibi Yoyo :)
Re:FireDAC - Refresh
« Odpověď #18 kdy: 08-11-2017, 15:10:50 »
Keďže to ušetrí prostriedky a čas, tak záujem mám.

Ja to myslel jen jako navrh nove property nastaveni pro report do Embarcadera. Jinak ta samotna lokalizace zaznamu (LocateRecord) bude rychla protoze se prohledava uz jen interni storage. Co zabere cas je prenos zaznamu z DBMS prave do te storage. A to je vlastne to co tady resime.

Rezim prenosu (FetchOptions.Mode) se momentalne pri volani Refresh ignoruje. Pri fmOnDemand se tak namisto hledani klice puvodne vybraneho zaznamu postupnym prenasenim packetu dokud neni zaznam nalezen natvrdo prenasi vsechny zaznamy (jakoby byl nastaven rezim fmAll). A pri rezimu fmAll, pokud se predchozi zaznam "hleda" pomoci indexu radku RecNo (protoze v datasetu neni klic) se zaznamy ziskavaji postupnym prenosem packetu dokud jich neni dostatek (jakoby byl nastaven rezim fmOnDemand).

No a pak jeste chybi nejake "vypnuti" te lokalizace posledne vybraneho zaznamu pri volani Refresh pro stav, kdy mas rezim fmOnDemand a vis ze po uprave parametru dotazu nemuze posledne vybrany zaznam v resultsetu existovat (nebo kdy neresis posledni pozici kurzoru). Aby se dalo hledani zcela vyhnout.

Tá lokalizácia pomocou ID sa dá potlačiť nastavením nejakých vlastností.

Ne v tomto pripade, tj. volani metody Refresh, implementace Delphi Tokyo.
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 Radek Červinka

  • Administrátoři
  • Padawan
  • *****
  • Příspěvků: 1762
  • Karma: 72
    • Verze Delphi: D5,D2007, DXE, DXE2 + 2 poslední (Tokyo)
    • O Delphi v češtině
Re:FireDAC - Refresh
« Odpověď #19 kdy: 09-11-2017, 08:56:14 »
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).

Já jsem u nás refresh vyřešil tak, že dám do DB dotaz, který mi vrátí jen množinu jen změněných záznamů (podle primárního klíče), z otevřené původní Firedac query ty řádky na úrovni DataSet.Table (což je interní storage ve které má firedac načtené data) odstraní, a nově získané tam přidá. Funguje to léta perfektně.

z pohledu následníka firedac query
Kód: [Vybrat]
procedure TXDataSet.gRefreshRows( sSQL:string; const sKeys: string; iId: Integer);
var
  adsRefresh: TAdQuery;
  s: string;
  iOrder: Integer;
  opt: TADDataSetLocateOptions;
  bmk: TBookmark;
  oDestRow:TADDatSRow;
  iRowIndex: Integer;
begin
  adsRefresh := TAdQuery.Create(nil);
  adsRefresh.Database := Self.Database;
  try
    // remove ORDER BY protoze subselekty to nesmi obsahovat
    s := LowerCase(sSQL);
    iOrder := Pos('order by', s);
    if iOrder > 0 then
      sSQL := Copy(sSQL, 1, iOrder - 1);

    // wrapni SQL
    sSQL := Format('SELECT T_Refresh.* FROM (%s) T_Refresh WHERE T_Refresh.%s = %d', [sSQL, sKeys, iId]);

//    MsgOk(sSQL);
    adsRefresh.SQL.Text := sSQL;
    adsRefresh.Open;
    DisableControls;
    iRowIndex:= -1;
    bmk := GetBookmark;
    try
      opt := []; // hledej od zacatku a odstran vsechny zaznamy z lokalnich dat
      while LocateEx(sKeys, iId, opt) do
      begin
        BeginBatch(True);
        try
          oDestRow := GetRow;
          if oDestRow <> nil then
          begin
            iRowIndex := oDestRow.Index;
            oDestRow.Delete();
            Table.Rows.Remove(oDestRow);
          end;
        finally
          EndBatch;
        end;
      end;

      // append refreshed records or not, if doesn't exist

      while not adsRefresh.Eof do
      begin
        if iRowIndex >= Table.Rows.Count then
          iRowIndex := -1;
        CopyOneRow(adsRefresh, [coRefresh, coAppend], iRowIndex);
        adsRefresh.Next;
      end;
    finally
      adsRefresh.Close;
      if BookmarkValid(bmk) then
        GotoBookmark(bmk);
      EnableControls;
    end;
  finally
    adsRefresh.Free;
    FreeBookmark(bmk);
  end;

a klíčová low level CopyOneRow, převzato z FireDac zdrojáků a upraveno

Kód: [Vybrat]

procedure TXDataSet.CopyOneRow(ASource: TDataset; AOptions: TADCopyDataSetOptions; iPos: Integer);
var

  eStatus: TUpdateStatus;
  oSrcRow, oDestRow: TADDatSRow;
  aMap: TADArrayOfInteger;
begin
  if (ASource = nil) or (ASource = Self) then
    Exit;

  StartWait;
  try
    // Run batch update.
    BeginBatch;
    try
      if coAppend in AOptions then
        eStatus := usInserted
      else
        eStatus := usModified;

      // Copy data
      if eStatus in [usInserted, usModified] then

        // Merge data into main table. Do not produce row version.
        if coRefresh in AOptions then begin
          if eStatus = usInserted then
          begin
            oDestRow := Table.NewRow(False);
            if iPos = -1 then
              Table.Rows.Add(oDestRow)
            else
              TADDatSTableRowList(Table.Rows).AddAt(oDestRow, iPos);
          end
          else
            oDestRow := GetRow();
          oSrcRow := TADDataSet(ASource).GetRow();
          if Length(aMap) = 0 then
            Table.MakeColumnMap(oSrcRow, aMap);
          Table.Import(oSrcRow, oDestRow, aMap);
          oDestRow.AcceptChanges();
        end
    finally
      EndBatch;
    end;
  finally
    StopWait;
  end;
end;



Embarcadero MVP - Czech republic

Offline chaloup

  • Mladík
  • **
  • Příspěvků: 85
  • Karma: 9
    • Verze Delphi: Delphi 10.2
Re:FireDAC - Refresh
« Odpověď #20 kdy: 09-11-2017, 09:18:07 »
Já jsem u nás refresh vyřešil tak, že dám do DB dotaz, který mi vrátí jen množinu jen změněných záznamů (podle primárního klíče), z otevřené původní Firedac query ty řádky na úrovni DataSet.Table (což je interní storage ve které má firedac načtené data) odstraní, a nově získané tam přidá. Funguje to léta perfektně.
Jak se řeší změny/přidané záznamy ostatních uživatelů? Co je T_Refresh?

Offline Radek Červinka

  • Administrátoři
  • Padawan
  • *****
  • Příspěvků: 1762
  • Karma: 72
    • Verze Delphi: D5,D2007, DXE, DXE2 + 2 poslední (Tokyo)
    • O Delphi v češtině
Re:FireDAC - Refresh
« Odpověď #21 kdy: 09-11-2017, 09:28:17 »
Já jsem u nás refresh vyřešil tak, že dám do DB dotaz, který mi vrátí jen množinu jen změněných záznamů (podle primárního klíče), z otevřené původní Firedac query ty řádky na úrovni DataSet.Table (což je interní storage ve které má firedac načtené data) odstraní, a nově získané tam přidá. Funguje to léta perfektně.
Jak se řeší změny/přidané záznamy ostatních uživatelů? Co je T_Refresh?

Kód: [Vybrat]
SELECT T_Refresh.* FROM (%s) T_Refresh

Vezme se originální query, to se obalí a dá se mu alias.

Ostatní záznamy, uživatel nevidí dokud si nedá manuální refresh nebo to nevynutím (což je stejná situace jako když jen sedíš u PC a nic neděláš, taky neuvidíš cizí). Tohle se používá při editaci jednoho záznamu. Samozřejmě se dá ta T_Refresh napsat aby vrátila i nové nebo změněné záznamy, pokud je dokážeš poznat. Ono ale většinou zákazníka moc nezajímají cizí záznamy a při různých kolizích to stejnak musíš otestovat v ten okamžik.



Embarcadero MVP - Czech republic

Offline Delfin

  • Hrdina
  • ****
  • Příspěvků: 362
  • Karma: 15
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
    • Ibi Yoyo :)
Re:FireDAC - Refresh
« Odpověď #22 kdy: 09-11-2017, 20:35:52 »
Tohle se používá při editaci jednoho záznamu.

Nevim zda to chapu spravne, ale k obcerstveni jednoho zaznamu existuje metoda RefreshRecord. Jinak nejvyssi efektivitu ziskas vlastnorucne psanym strankovanim. V SQL pomoci LIMIT a OFFSET pripadne rozsahem klicu (s dotazenim vice zaznamu v pripade absence zaznamu v okne).
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 Radek Červinka

  • Administrátoři
  • Padawan
  • *****
  • Příspěvků: 1762
  • Karma: 72
    • Verze Delphi: D5,D2007, DXE, DXE2 + 2 poslední (Tokyo)
    • O Delphi v češtině
Re:FireDAC - Refresh
« Odpověď #23 kdy: 09-11-2017, 23:21:58 »
Nevim zda to chapu spravne, ale k obcerstveni jednoho zaznamu existuje metoda RefreshRecord.

Byl tam nejaky problem u slozenych dotazu s vice join
Embarcadero MVP - Czech republic

 

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í:
Kolik je šest plus čtyři (slovem):