Programování v JavaFX: aktualizace záznamů, uložení a zrušení změn

Jaromír Vojtaj 3. 12. 2015

Minulý třináctý díl našeho seriálu o použití jazyka JavaFX byl věnován kontrole editačních polí. Ukázali jsem si kontrolu jak obsahu, tak formátu jednotlivých typů editačních polí. V dnešním čtrnáctém dílu se budeme věnovat uložení aktualizovaných záznamů a případným zrušením provedených změn.

V minulém dílu jsme ukončili všechny potřebné kontroly obsahu a formátu editačních polí. To nám bude teď sloužit jako základ pro aktualizaci vybraného záznamu a uložení aktualizovaných hodnot zpět do tabulky. Za tímto účelem si připravíme obecnější proceduru, která bude sloužit pro ukládání dat do tabulky pomocí SQL příkazů. To znamená, že nám bude sloužit jak pro ukládaní aktualizovaných záznamů, tak záznamů nových, přidávaných do tabulky. Zmíněná procedura může vypadat např. takto:

private void dataInsert(final String query, final String[] types, final ArrayList items){   //1
        PreparedStatement pStat = null;                             //2
        String typ = null;                                  //3
        String typStr = null;                                   //4
        CONN = connDB("fxguide", "fxguide");                            //5
        try { CONN.setAutoCommit(false);                            //6
            pStat = CONN.prepareStatement(query);                       //7
            for (int i=1;i<=items.size();i++){                           //8
                typ=types[i-1];                                 //9
                switch (typ){                                   //10
                    case "INT": { typStr=items.get(i-1).toString();             //11
                        pStat.setObject(i, typStr, Types.INTEGER); break; }         //12
                    case "STR": { typStr=items.get(i-1).toString();             //13
                        pStat.setString(i, typStr); break; }                    //14
                    case "DBL": { typStr=items.get(i-1).toString();             //15
                        pStat.setObject(i, typStr, Types.DOUBLE); break; }          //16
                    case "DTM": { typStr=items.get(i-1).toString();             //17
                        pStat.setObject(i, typStr, Types.DATE); break; } } }            //18
            pStat.executeUpdate();                              //19
            CONN.commit();                                  //20
        } catch (SQLException e) { e.getMessage();
            try { CONN.rollback(); }
            catch (SQLException e1) { e1.getMessage(); }
        } finally { if (pStat != null) {
            try { pStat.close(); }
            catch (SQLException e) { e.getMessage(); }
            try { CONN.close(); }
            catch (SQLException e) { e.getMessage(); }} } }

Jak je z kódu patrné, procedura je trochu komplikovanější, takže si k ní uvedeme několik podrobností:

  1. řádek – procedura má tři parametry – SQL příkaz jako řetězec, pole řetězcových proměnných, které charakterizují typ ukládaných údajů a pole samotných údajů
  2. řádek – deklaruje se lokální proměnná příslušného typu
  3. řádek – deklaruje se lokální proměnná pro rozhodovací strom
  4. řádek – deklaruje se lokální proměnná pro uložení jednotlivých údajů
  5. řádek – procedura se přihlašuje k databázi
  6. řádek – začíná smyčka pro záchyt výjimek a ruší se automatické provedení změn
  7. řádek – připravuje se zadaný SQL příkaz
  8. řádek – startuje se smyčka pro celkový počet zadávaných údajů
  9. řádek – pro každý běh se ukládá příslušný typ ukládaného údaje
  10. řádek – startuje se rozhodovací příkaz. Pro upřesnění: zde je jako řídící proměnná použit typ String. To je možné od verze Java 7, dříve bylo nutné používat pouze řídící proměnné typu Integer!
  11. řádek – pro celočíselné údaje se uloží příslušná hodnota a převede se na řetězec
  12. řádek – do SQL příkazu se přidá proměnná v daném pořadí a nastaví se příslušný typ Integer
  13. řádek – pro řetězcové údaje se uloží příslušná hodnota a převede se na řetězec
  14. řádek – do SQL příkazu se přidá proměnná v daném pořadí, typ není pro String nutné nastavovat
  15. řádek – pro desetinné údaje se uloží příslušná hodnota a převede se na řetězec
  16. řádek – do SQL příkazu se přidá proměnná v daném pořadí a nastaví se příslušný typ Double
  17. řádek – pro údaje data se uloží příslušná hodnota a převede se na řetězec
  18. řádek – do SQL příkazu se přidá proměnná v daném pořadí a nastaví se příslušný typ Date
  19. řádek – kompletní SQL příkaz se provede
  20. řádek – potvrdí se provedení změn

Pak už následuje pouze blok zachycení výjimek včetně zrušení všech provedených změn při jakékoliv chybě. Výkonnou proceduru máme tedy připravenou a můžeme se pustit do jejího volání z procedury save_Update. Tu zde nebudeme uvádět celou (na začátku je blok pro kontrolu obsahu a formátu zadaných údajů v editačních polích) a začneme až příkazem, který se provádí v momentě, kdy jsou všechny zadané údaje v pořádku:

else {
       dataItems.clear();                                       //1

       LocalDate sqlDate = null;                                    //2
       DateTimeFormatter formatter = DateTimeFormat.forPattern("d.M.yyyy");             //3
       try { sqlDate = formatter.parseLocalDate(u_Datum.getText()); }                   //4
       catch (IllegalFieldValueException e) { }                             //5
       catch (IllegalArgumentException f) { }                               //6

       dataItems.add(u_Cele.getText());                                 //7
       dataItems.add(u_Desetinne.getText());                                //8
       dataItems.add(u_Maledes.getText());                              //9
       dataItems.add(u_Text.getText());                                 //10
       dataItems.add(sqlDate.toString());                               //11
       dataItems.add(pid);                                      //12

       dataInsert("UPDATE udaje SET celecis=?,descis=?,maledes=?,retezec=?,datum=? WHERE id=?;",    //13
               new String[] {"INT", "DBL", "DBL", "STR", "DTM", "INT"},                 //14
               dataItems);                                      //15

       showFmt();                                           //16
       tf_RO();                                             //17
       a_Button.setDisable(true);                                   //18
       e_Button.setDisable(true);                                   //19
       u_Button.setDisable(true);                                   //20
       tabPane.getSelectionModel().select(0); } }                           //21

Uložení zadaných údajů se skládá z několika sekcí – definice správného formátu zadávaného data, uložení všech zadávaných údajů do pole proměnných, volání výkonné procedury se skutečnými parametry a následné akce po úspěšném uložení údajů do tabulky. Konkrétněji to pak vypadá takto:

  1. řádek – nuluje se obsah pole pro uložení údajů
  2. řádek – pomocí knihovny Joda-Time se deklaruje příslušná proměnná
  3. řádek – pomocí stejné knihovny se definuje způsob formátování
  4. řádek – do proměnné se pomocí deklarovaného formátu ukládá obsah příslušného pole.
  5. řádek – zachycení prvního možného druhu výjimky
  6. řádek – to samé pro další druh
    Tyto příkazy jsou jenom pro doplnění celého bloku záchytu výjimek. Chyba zde samozřejmě nastat nemůže, protože ji máme ošetřenou na začátku procedury. Takto složitě je nutné upravit datum proto, že je nutné zajistit jeho formát nutný pro uložení pomocí SQL příkazu
  7. řádek – uloží se pole s celým číslem
  8. řádek – uloží se pole s desetinným číslem
  9. řádek – uloží se pole s malým desetinným číslem
  10. řádek – uloží se pole s textem
  11. řádek – pro uložení data se použije proměnná z předchozího bloku
  12. řádek – uloží se hodnota klíčového pole pomocí deklarované hodnoty ve vybraném záznamu
  13. řádek – volá se výkonná procedura. Prvním parametrem je SQL příkaz pro změnu údajů v záznamu. Konkrétní hodnoty jsou nahrazené otazníkem
  14. řádek – druhým parametrem je pole s typem jednotlivých údajů
  15. řádek – třetí parametr je pak pole s definovanými hodnotami
    Při volání výkonné procedury je nutné dbát na to, aby bylo v souladu několik věcí:
    • správně formulovaný a zapsaný SQL dotaz (název tabulky a sloupců, definice klíčové položky, atd.)
    • pole typů dat musí mít na správném postu správný typ údaje, jinak dojde k chybě při ukládání
    • pole typů dat musí mít stejný počet položek, jako má SQL dotaz otazníků
    • pole uložených údajů musí mít také správný počet, pozici a případně formát pro jednotlivé položky
  16. řádek – volá se procedura pro zobrazení údajů z tabulky
  17. řádek – všechna editační pole jsou nastavena pouze pro čtení
  18. řádek – tlačítko pro aktivaci aktualizace se nastaví jako nefunkční
  19. řádek – tlačítko pro uložení změn se nastaví jako nefunkční
  20. řádek – tlačítko pro zrušení se nastaví jako nefunkční
  21. řádek – automaticky se přejde na první záložku, aby bylo vidět výsledek aktualizace v tabulce

Abychom mohli uložení vyzkoušet, musíme nejprve umlčet chybové hlášení a do lokálních proměnných procedury samexam4 přidat jeden řádek:

private ArrayList<Object> dataItems = new ArrayList<Object>();

Pak už můžeme aplikaci spustit, vybrat si první řádek v tabulce a aktivovat aktualizace. Následně zadáme všechny údaje tak, jak to ukazuje první obrázek v galerii. Klikneme na tlačítko Uložit změny a výsledek vidíme na druhém obrázku galerie. Z obrázku si můžeme povšimnout tří základních skutečností:

  • změny v zadaných hodnotách byly uloženy a vybraný záznam byl aktualizován
  • na rozdíl od ostatních záznamů je vidět hodnota ve sloupci Male des. To je způsobeno tím, že jsme zadali hodnotu, která je mimo rozsah, který malé hodnoty nezobrazuje
  • aktualizovaný záznam se přesunul na poslední místo v tabulce

Třetí obrázek v galerii nám ukazuje vzhled druhé záložky, kde je aktivní pouze tlačítko pro mazání záznamů. Pokud bychom chtěli ostatní tlačítka znovu aktivovat, museli bychom udělat dvojklik na vybraný záznam v tabulce. Ještě si ukážeme nápravu nesprávného řazení záznamů v tabulce. Změnu provedeme jednoduše změnou SQL příkazu v proceduře showFmt:

final String query = "SELECT * FROM udaje ORDER BY id;";

Výsledek nového řešení je vidět na čtvrtém obrázku galerie. Poslední věc, kterou si dnes ukážeme, bude zároveň i poslední součástí kapitoly o aktualizaci záznamů. Ve formuláři máme tlačítko Zrušit změny, které jsme zatím jenom dočasně a pokusně použili při práci na kontrole správného formátu dat. Nyní si ukážeme takové použití, pro které bylo stvořeno. Jedná se o to, že někdy můžeme provádět více změn v záznamu a můžeme o nich ztratit přehled. Je samozřejmě možné se vrátit zpět na tabulku a znovu si vyvolat záznam s původními hodnotami. My už jsme si ale připravili v proceduře rec_Update uložení aktuálních údajů před zahájením jejich úprav. Abychom mohli nastavit „zpětný chod“, stačí udělat dva kroky. Jako první si vytvoříme výkonnou proceduru:

widgety

private void cancel_Update() {
        u_Cele.setText(data.get(0).toString());
        u_Desetinne.setText(data.get(1).toString());
        u_Maledes.setText(data.get(2).toString());
        u_Text.setText(data.get(3).toString());
        u_Datum.setText(data.get(4).toString()); }

Jako další si přidáme volání této procedury k příslušnému tlačítku a můžeme vše vyzkoušet. Spustíme aplikaci, vybereme první řádek tabulky a provedeme změny třeba tak, jak to ukazuje poslední obrázek v galerii. Po stisku tlačítka na zrušení změn dostaneme zpět původní hodnoty v odpovídajících editačních polích a můžeme se pustit do dalšího kola jejich úprav. Tímto konstatováním ukončíme dnešní díl i kapitolu o aktualizaci záznamů a do přílohy přiložíme aktuální stav dotčené procedury: samexam4.java.

V dnešním dílu jsme ukončili ukládání aktualizovaných záznamů do tabulky. Také jsme si ukázali jednoduchý způsob pro zrušení provedených změn v editačních polích. V příštím dílu se zaměříme na vkládání nových záznamů do tabulky a jejich správné uložení.

Našli jste v článku chybu?
Vitalia.cz: 5 důvodů, proč jet na výlov rybníka

5 důvodů, proč jet na výlov rybníka

DigiZone.cz: Test LG 55UH750V aneb Cena/výkon

Test LG 55UH750V aneb Cena/výkon

Vitalia.cz: Voda z Vltavy před a po úpravě na pitnou

Voda z Vltavy před a po úpravě na pitnou

Vitalia.cz: Inspekce našla nelegální sklad v SAPĚ. Zase

Inspekce našla nelegální sklad v SAPĚ. Zase

DigiZone.cz: Nova opět stahuje „milionáře“

Nova opět stahuje „milionáře“

120na80.cz: Co je padesátkrát sladší než cukr?

Co je padesátkrát sladší než cukr?

DigiZone.cz: Světový pohár v přímém přenosu na ČT

Světový pohár v přímém přenosu na ČT

Lupa.cz: Patička e-mailu závazná jako vlastnoruční podpis?

Patička e-mailu závazná jako vlastnoruční podpis?

Lupa.cz: Jak se prodává firma za miliardu?

Jak se prodává firma za miliardu?

Podnikatel.cz: Babišovi se nedá věřit, stěžovali si hospodští

Babišovi se nedá věřit, stěžovali si hospodští

Vitalia.cz: Kterou dýni můžete jíst za syrova?

Kterou dýni můžete jíst za syrova?

Vitalia.cz: 5 pravidel proti infekci močových cest

5 pravidel proti infekci močových cest

DigiZone.cz: Parlamentní listy: kde končí PR...

Parlamentní listy: kde končí PR...

DigiZone.cz: Rapl: seriál, který vás smíří s ČT

Rapl: seriál, který vás smíří s ČT

Podnikatel.cz: Dva měsíce na EET. Budou stačit?

Dva měsíce na EET. Budou stačit?

Podnikatel.cz: Instalatér, malíř a elektrikář. "Vymřou"?

Instalatér, malíř a elektrikář. "Vymřou"?

Vitalia.cz: Tahák, jak vyzrát nad zápachem z úst

Tahák, jak vyzrát nad zápachem z úst

Lupa.cz: Další Češi si nechali vložit do těla čip

Další Češi si nechali vložit do těla čip

DigiZone.cz: Wimbledon na Nova Sport až do 2019

Wimbledon na Nova Sport až do 2019

DigiZone.cz: DVB-T2 ověřeno: seznam TV zveřejněn

DVB-T2 ověřeno: seznam TV zveřejněn