sobota 12. května 2012

Vyřazení duplikátních výsledků z dtb

Dnes jsem hledal možnost, jak vyřadit duplikátní záznamy ve výsledcích vrácené z databáze pomocí GORM. Protože jsem už používal dotazy pomocí třídy Criteria v Hibernate, tak jsem nakonec našel tuto konstrukci:
NejakaEntita.createCriteria().list() {
    resultTransformer Criteria.DISTINCT_ROOT_ENTITY // this is it
}

Good to know. Význam té konstrukce jsem zatím nezkoumal, na to snad bude čas někdy jindy. Hlavní je, že funguje.

čtvrtek 10. května 2012

Moje první MySQL procedura

Včera jsem napsal svoji první MySQL proceduru. Měl za úkol vygenerovat náhodné číslo, které má 10 číslic a je jedinečné v celé databázi.

create procedure generaterc()
begin
declare _rc varchar(255);  --tady jsem měl chybu
declare _id int;
set _id = 1;
while _id < ((select count(*) from patient) + 1) do
    begin
    set _rc = cast(FLOOR(1000000000 + (RAND() * 8999999999)) AS char);  
    if not exists(select * from patient where patient.rc = _rc) then
        update patient set rc=_rc where id=_id;
        set _id=_id+1;          
    end if;
    end;
end while;  
end
Poznámka pod čarou:
Proměnné, které chceme pak dávat jako hodnotu do sloupců databáze, by měly mít stejný datový typ jako ten sloupec. Měl jsem v tabulce sloupec rc, který byl typu varchar(255). Proměnnou jsem však deklaroval jako declare _rc char; a to způsobilo nekompatibilní dat. typ. http://stackoverflow.com/questions/10524573/mysql-procedure-random-number-generating

Zjištění:
V databázi s 82 618 řádky funkce vůbec nedoběhne do konce, a to jsem ji nechal běžet přes 30 min. Nakonec jsem ty čísla náhodně negeneroval :)

středa 9. května 2012

PDF renderování a čeština

Včera jsem měl za úkol vyřešit problém s kódováním češtiny v PDF dokumentu. Kolegové, kteří na tom dělali, si nevěděli rady (nebo se s tím nechtěli párat), tak to přesunuli na mě...
V projektu používáme plugin Grails Rendering pro generování PDF souboru. Používání bylo jednoduché, jenže zase české znaky se nezobrazovaly. Bylo potřeba přidat správný font.

@font-face {
        src: url(file:c:/windows/fonts/arialuni.ttf);
        -fs-pdf-font-embed: embed;
        -fs-pdf-font-encoding: Identity-H;
}
Takhle se vše zobrazovalo správně. Problém byl ale v tom, že odkaz na font byl funkční jen pro Windows. OK, tak prostě se ten soubor s fontem zkopíroval do web-app/font složky (složka s HTML a CSS a obrázky, která se nekompiluje). Komplikací poté ale bylo, že nešlo na ten soubor odkazovat:

@font-face {
        src: url(file:${resource(dir:'font', file: 'ARIALUNI.TTF')});
        -fs-pdf-font-embed: embed;
        -fs-pdf-font-encoding: Identity-H;
}
A hned NullPointerException. Naštěstí jsem pak našel na StackOverlow, jak to někdo také řešil. A také jsem přehlídl důležitou větu v manuálu (RTFM): All links to resources (e.g. images, css) must be accessible by the application . This is due to the linked resources being accessed by application and not a browser. Takže řešením bylo nějak takhle (na soubor se muselo odkazovat jako na soubor z PC, ne přes URL):

@font-face {
        src: url(file:${czechFontPath});
        -fs-pdf-font-embed: embed;
        -fs-pdf-font-encoding: Identity-H;
}



úterý 1. května 2012

DBF soubor s českými znaky

České čárky a háčky,to je občas velké zlo v kódování. A ještě větší zlo je,když toto kódování nevíte a ani neumíte zjistit. V současném projektu je 1 z úkolů migrace databáze. Jenže databáze starého systému,který je starý a k tomu ještě desktopový, že jsem tu databázi viděl poprvé (slyšel podruhé). Jednalo se o databázi foxpro a hromada souborů s koncovkou .dbf.
Myslel jsem, že vše proběhne bez problému. Jako první jsem stáhl z netu nějaké programy pro zobrazování,ale bohužel žádná neuměla české znaky přečíst (např. č). Pak jsem koukal i přímo po java knihovnách. Nejlepší byl tento: http://www.hxtt.com/orderdbf.html, akorát stál prachy,takže nic pro studenty. Trial verze umožňovala zobrazit jen 1000 prvních řádků... Ale plusem byl ten,že jsem konečně zjistil kódování dbf souboru (Cp1250).
Po delším hledání jsem narazil na program od českých autorů: http://www.pspad.com/cz/dbfview.htm. Ten funguje skvěle,doporučuji. Migrace samotné provedeme konverzí na csv a pak načtení csv do databáze.

čtvrtek 26. dubna 2012

Jak získat lokalizované texty z .properties souboru

Grails má dobře zmáklé message.properties soubory pro internacionalizaci aplikací. Díky tomu lze jednoduše udělat vícejazyčné aplikace. V dokumentaci je pěkně popsané, jak získat texty z těchto souborů z view nebo controlleru a taglib. Trochu však pozapomněli popsat, jak získat z doménových tříd a servisních tříd. Hodí se to, když chci v service třídě vyházet výjimku s vlastním textem.

Je potřeba deklarovat na začátku třídy field proměnnou (česky lokální?):
def messageSource
Grails do této proměnné provede automaticky DI. Pak lze pomocí této proměnné získat poměrně snadno texty z message.properties:
messageSource.getMessage("some.entity.label", null, "", LocaleContextHolder.getLocale())
getMessage() metoda má několik variant (přetěžovaných metod). Tu, kterou jsem použil, bere 4 parametry - první String je kód z message.properties souboru, druhý jsou možné argumenty v textu (žádné nemám), třetí je defaultní text a čtvrtý je Locale instance (což je zde ten, který má klient). Více zde.

neděle 22. dubna 2012

mysqldump v Grails

Dnes jsem poprvé vyzkoušel příkaz "mysqldump". Tento příkaz provede dump databáze v MySQL, což znamená, že se vytvoří skript pro kompletní (nebo i jiný) backup. Příkaz chci vyvolat v service třídě. Zatím jsem vykoumal toto:

public void createMySQLDump() {
        String username = grailsApplication.config.dataSource.username
        String password =  grailsApplication.config.dataSource.password
        "mysqldump --user=${username} --password=${password} --all-databases --result-file=mysql-dump-${new Date().format("ddMMyyyy")}.sql".execute()
    }
Tento dump vytvoří backup pro všechny dostupné databáze daného uživatele. Co jsem nepochopil, tak nefunguje mysqldump tímto způsobem:
"mysqldump --user= ${username} --password= ${password} --all-databases > C:\\mysql-dump-${new Date().time}.sql"
Jsem pak četl na jednom blogu, že znak ">" nelze použít, ale Grails to nijak neoznámí. Takže bacha.

Edit: Zjistil jsem, že dataSource objekt nefunguje spolehlivě pro zjištění uživ. jména a hesla do databáze, a je lepší použít grailsApplication objekt. Oba jsou pomocí DI automaticky vkládány do service tříd.

úterý 10. dubna 2012

MySQL - získání dalšího čísla při autoincrement

Potřeboval jsem získat ID další entity, která se má teprve uložit do databáze. V MySQL existuje na tohle příkaz:
SHOW TABLE STATUS WHERE Name='nazev_tabulky'
Vrátí to jeden řádek, kde sloupec "Auto_increment" nese v sobě hodnotu čísla, která bude přiřazena další entitě. V Groovy je celá metoda nějak takhle (pro tabulku/entitu "invoice"):

public long getNextInvoiceNumber() {
        def sql = new Sql(dataSource)
        def firstRow = sql.firstRow('SHOW TABLE STATUS WHERE Name=\'invoice\'')
        def nextInvoiceNumber = Long.parseLong(firstRow.Auto_increment.toString())
        return nextInvoiceNumber
}