checkExist()

checkExist() je jedna ze „standardizovaných“ statických metod na tabulkách v Dynamics AX. Doplňuje metodu exist() tak, že navíc zobrazuje chybovou zprávu v infologu (znění chyby bývá implementováno v samostatné metodě txtNotExist()). Hodně týmů vytváří jen medody find() a exist(), což je škoda, protože vypsání chybové zprávy v případě nenalezeného záznamu je běžný scénář a je zbytečné takovou logiku duplikovat na různých místech kódu volajících exist(), nemluvě o nemožnosti změnit text chyby na jediném centrálním místě.

Trochu překvapivě se i v takto jednoduché metodě dá chybovat. Dnes jsem takovou chybu objevil v průběhu revize kódu a bohužel jsem ji našel i na mnoha jiných místech, včetně standardního kódu AX.

Mějme následující kus kódu, který validuje existenci _bomId v BOMTable a provede nějakou akci, pokud validace uspěje:

if (BOMTable::checkExist(_bomId))
{
    BOMTable::setCheckBOM(_bomId, false);
}

Logický předpoklad je, že pokud je tento kód zavolán s prázdným _bomId (což se může snadno stát), setCheckBOM() se neprovede a zobrazí se nějaká informace o neexistenci BOMu. Skutečný výstup ale je:

„Cannot edit a record in Bills of materials (BOMTable). The record has never been selected.“

Validace zřejmě uspěla, přestože žádný záznam s prázdným BOMId neexistuje (a ani nemůže, protože jde o povinné pole). Neplatná hodnota se tak dostala do dalšího zpracování a způsobila tam vyhození výjimky.

Důvod je dobře patrný z kódu metody checkExist():

static boolean checkExist(BOMId bomNum)
{
    if (bomNum && ! BOMTable::exist(bomNum))
        return checkFailed(strfmt(BOMTable::txtNotExist(),bomNum));
 
    return true;
}

Je-li bomNum prázné, hned první podmínka v if není splněna a metoda checkExist() vrátí true! Neočekávaná prázdná hodnota je tak úspěšně zvalidována a celá validace ztratila smysl.

Jak to má správně vypadat?

Stačí odebrat první část podmínky a nechat celou validační logiku na metodě exist(). Od toho metoda exist() také je.

static boolean checkExist(BOMId bomNum)
{
    if (!BOMTable::exist(bomNum))
        return checkFailed(strfmt(BOMTable::txtNotExist(),bomNum));
 
    return true;
}

Protože ani metoda exist() na BOMTable není implementována nejlépe, správně vrací false pro prázdnou hodnotu bomNum. Podmínka v checkExist() je tedy splněna, metoda vrátí false a do infologu vypíše „Bill of materials  does not exist“.