2012年10月29日星期一

How to using code create purchase order


Purchase Order using X++
In this post we will learn the below using X++ :
 1) How to Create Purchase Order
 2) How to Create Purchase Order Line
 3) How to Post Purchase Order

static void THK_createPurchaseOrder(Args _args)
{
    PurchTable      purchTable;
    PurchLine       pline;
    NumberSeq       ns;
    PurchID         pid;
    PurchFormLetter pl;
;
    //Create Purchase Order
    ns                      = NumberSeq::newGetNumFromCode(SalesParameters::numRefSalesId().NumberSequence);
    purchTable.initValue();
    pid                     = ns.num();
    purchTable.PurchId      = pid;
    purchTable.OrderAccount = "4202";
    purchTable.initFromVendTable();
    purchTable.insert();

    //Create Purchase Line
    pline.clear();
    pline.PurchId   = pid;
    pline.ItemId    = "1109";
    pline.createLine(NoYes::Yes,NoYes::Yes,NoYes::Yes,NoYes::Yes,NoYes::Yes,NoYes::Yes);
    info("Purchase Order Created Sucessfully");

    //Post the PO
    pl = PurchFormLetter::construct(DocumentStatus::Invoice);
    pl.update(PurchTable::find(pid), pid, SystemDateGet(),PurchUpdate::All,AccountOrder::None,false,true);
    info("Posted Sucessfully");
}

How to using code create and post inventory jounral


Create & Post Inventory Journal in AX 2009
Following is job which will create and post the Inventory Journal in ax 2009

static void THK_createMovJournal(Args _args)
{
    InventJournalTable      journalTable;
    InventJournalTrans      journalTrans;
    InventJournalTableData  journalTableData;
    InventJournalTransData  journalTransData;
    InventTable             inventTable;
    inventDim               tmpinventDim;
    Counter                 cnt;
    InventJournalCheckPost  journalCheckPost = new InventJournalCheckPost();
    DialogButton            dbtn;
;
    journalTableData = JournalTableData::newTable(journalTable);
    journalTransData = journalTableData.journalStatic().newJournalTransData(journalTrans,journalTableData);

    // create JournalTable

    journalTable.clear();

    journalTable.JournalId      = journalTableData.nextJournalId();
    journalTable.JournalType    = InventJournalType::Movement;
    journalTable.JournalNameId  = journalTableData.journalStatic().standardJournalNameId(journalTable.JournalType);

    journalTableData.initFromJournalName(journalTableData.journalStatic().findJournalName(journalTable.JournalNameId));

    // create JournalTrans
    select firstonly inventTable;
    for(cnt=1;cnt<10;cnt++)
    {
        journalTrans.clear();
        journalTransData.initFromJournalTable();

        journalTrans.TransDate              = systemdateget() + 1 div 2;
        journalTrans.ItemId                 = '1103';    //inventTable.ItemId;
        journalTrans.Qty                    = 100;
        journalTrans.CostAmount             = 100;
        journalTrans.LedgerAccountIdOffset  = '110170';

        // Dimension details

        tmpinventDim.InventLocationId  = '11';
        journalTrans.InventDimId    ='00000061_069'; //InventDim::findOrCreate(inventDim).inventDimId;

        journalTransData.create();
    }

    journalTable.insert();

    // Call the static method to post the journal
    if(InventJournalCheckPost::newPostJournal(journalTable).validate())

    if(box::yesNo("Do you want to Post Now?",DialogButton::No)==DialogButton::Yes)
    {
        InventJournalCheckPost::newPostJournal(journalTable).run();
    }
    else
    {
        box::info("Not Posted");
    }
    info("done");
}

How to using code create sales order


/*sales Order using X++
Hi,In this post we will learn the below using X++ :
 1) How to Create Sales Order
 2) How to Create Sales Order Line
 3) How to Post Sales Order
*/
public static void THK_createSalesOrderDemo(Args _s)
{
// Create the Sales Order
    SalesTable      salesTable;
    SalesLine       sl;
    
    SalesId         sid;
    NumberSeq       NumberSeq;
    SalesFormLetter fl;
;
    NumberSeq           = NumberSeq::newGetNumFromCode(SalesParameters::numRefSalesId().numberSequence);
    sid                 = NumberSeq.num();
    
    //create sales order header
    salesTable.SalesId  = sid;
    salesTable.initValue();
    salesTable.CustAccount = "1101";
    salesTable.initFromCustTable();
    salesTable.insert();

    //Create the Sales Line with the created Sales Order
    sl.SalesId = sid;
    sl.ItemId  = "1109";
    sl.CreateLine(NoYes::Yes,NoYes::Yes,NoYes::Yes,NoYes::Yes,NoYes::Yes,NoYes::Yes);

    info("Sales Order Created with Line");

    //How to Post the Sales Order Invoice
    fl=SalesFormLetter::construct(DocumentStatus::Invoice);
    fl.update(SalesTable::find(sid));
    info("Sales Order Posted");
}

How to using code deploy SSRS Reports to AX 2012



Following code can be used to deploy SSRS reports in Ax 2012.
However make sure that this code runs from the client, and not as CIL (otherwise you will get run time errors)
I can run this below code as a job and works fine.


please Note : This code will only work in AX 2012 as in AX 2009/4.0/3.0 there were no SSRSReport Classes.

static void THK_deploySSRSReportDemo(Args _args)
{
    SSRSReportManager       mgr = new SSRSReportManager();
    SSRSReportConceptNode   node = new SSRSReportConceptNode();
;
    node=TreeNode::findNode(@"\\SSRS Reports\Reports\SalesInvoice");
    mgr.deploymentStart();
    mgr.deployReport(node);
    mgr.deploymentEnd();
}

How to Convert/Upgrade MorphX Report to SSRS in Dynamics AX


One of the major change in Dynamics AX 2012 is related to reporting services. Though we were able to develop some SSRS reports in AX 2009 as well with limitted framework functionality. However, in AX 2012 SSRS reporting framework is much more enhanced. Currently, you can import your AX traditional reports of MorphX in 2012 with no change. However, you cannot develop new MorphX reports in 2012. So this is the right time to move all your MorphX reports to SSRS as in future releases of AX MorphX framework will be completey removed.

In order to migrate AX reports to SSRS report following are some important points
        1.       Create a new query and make exactly the same query used in X++ report.
        2.       Move all your business logic to RDP (Report data provider) class.
        3.       AutoDesign reports of X++ will be replaced by AutoDesign in SSRS reports.
        4.       Generated Design on X++ report will be replaced by PrecisionDesign in SSRS reports.

Please have a look on the guidance to upgrade report here.
http://technet.microsoft.com/en-us/library/gg724106.aspx

How to revised(synchronization) table and field ID in Dynamics AX data dictionary

if a table ID or field ID is changed in Dynamics AX, data are lost during synchronization, because the table with the old ID (and containing data) is dropped at the beginning and then a new table is created with the same structure but a different ID.The same is valid analogically for table fields.The data loss can be prevented in several ways (e.g. by data export and reimport), but one solution is really simple and painless. Realize how the situation looks in AX after the ID change (e.g. after installation of a layer with different IDs) but before the database synchronization: Data are still in the database Table metadata in AOT contain the new ID Data in SqlDictionary table contain the old ID So it’s not necessary to export data or to put old IDs down, all information is still in the system. You just have to secure that synchronization is not run prematurely.You can identify all changed IDs by comparing values in AOT with values in SqlDictionary. And the update of SqlDictionary to the new ID can prevent the regeneration of database objects during synchronization. I use several scripts for this purpose, this is the simplest one:


The other day we upgraded to Cumulative Update 3 for Dynamics AX 2012. After that we got some problems in the SqlDictionary table - several table and field IDs did not much those in the AOT anymore.One of our developers found this post, which contained a job fixing such issues. We had to correct the job a bit, otherwise it failed when trying to process Views or update field IDs that had been "swapped" during upgrade (e.g. before: fieldId1 = 6001, fieldId2 = 6002; after installing CU3: fieldId1 = 6002, fieldId2 = 6001).This is the final version of the job. I know the change violates DRY principle, but for an ad-hoc job it is probably OK


static void THK_fixTableAndFieldIds(Args _args)
{
    Dictionary dictionary = new Dictionary();
    SysDictTable dictTable;
    DictField dictField;
    TableId tableId;
    FieldId fieldId;
    SqlDictionary sqlDictionaryTable;
    SqlDictionary sqlDictionaryField;

    setPrefix("Update of data dictionary IDs");
    tableId = dictionary.tableNext(0);
    ttsbegin;

    while (tableId)
    {
        dictTable = new SysDictTable(tableId);

        setPrefix(dictTable.name());

        if (!dictTable.isSystemTable() && !dictTable.isView())
        {
            //Finds table in SqlDictionary by name in AOT, if ID was changed.
            //Empty field ID represents a table.
            select sqlDictionaryTable
                where   sqlDictionaryTable.name     == dictTable.name()
                &&      sqlDictionaryTable.fieldId  == 0
                &&      sqlDictionaryTable.tabId    != dictTable.id();

            if (sqlDictionaryTable)
            {
                info(dictTable.name());
                //Updates table ID in SqlDictionary
                if (ReleaseUpdateDB::changeTableId(
                                                    sqlDictionaryTable.tabId,
                                                    dictTable.id(),
                                                    dictTable.name())
                                                   )
                {
                    info(strFmt("Table ID changed (%1 -> %2)", sqlDictionaryTable.tabId, dictTable.id()));
                }
            }

            fieldId = dictTable.fieldNext(0);

            //For all fields in table
            while (fieldId)
            {
                dictField = dictTable.fieldObject(fieldId);

                if (dictField.isSql() && !dictField.isSystem())
                {
                    //Finds fields in SqlDictionary by name and compares IDs
                    select sqlDictionaryField
                        where   sqlDictionaryField.tabId    == dictTable.id()
                        &&      sqlDictionaryField.name     == dictField.name()
                        &&      sqlDictionaryField.fieldId  != 0
                        &&      sqlDictionaryField.fieldId  != dictField.id();

                    if (sqlDictionaryField)
                    {
                        //Updates field ID in SqlDictionary
                        if (ReleaseUpdateDB::changeFieldId(
                                                            dictTable.id(),
                                                            sqlDictionaryField.fieldId,
                                                            -dictField.id(),
                                                            dictTable.name(),
                                                            dictField.name())
                                                           )
                        {
                            info(strFmt("Pre-update: Field %1 - ID changed (%2 -> %3)",
                                dictField.name(),
                                sqlDictionaryField.fieldId,
                                -dictField.id()));
                        }
                    }
                }
                fieldId = dictTable.fieldNext(fieldId);
            }

            fieldId = dictTable.fieldNext(0);

            //For all fields in table
            while (fieldId)
            {
                dictField = dictTable.fieldObject(fieldId);

                if (dictField.isSql() && !dictField.isSystem())
                {
                    select sqlDictionaryField
                        where   sqlDictionaryField.tabId    == dictTable.id()
                        &&      sqlDictionaryField.name     == dictField.name()
                        &&      sqlDictionaryField.fieldId  < 0;

                    if (sqlDictionaryField)
                    {
                        //Updates field ID in SqlDictionary
                        if (ReleaseUpdateDB::changeFieldId(
                                                            dictTable.id(),
                                                            sqlDictionaryField.fieldId,
                                                            -sqlDictionaryField.fieldId,
                                                            dictTable.name(),
                                                            dictField.name())
                                                           )
                        {
                            info(strFmt("Final update: Field %1 - ID changed (%2 -> %3)",
                                dictField.name(),
                                sqlDictionaryField.fieldId,
                                -sqlDictionaryField.fieldId));
                        }
                    }
                }
                fieldId = dictTable.fieldNext(fieldId);
            }
        }
        tableId = dictionary.tableNext(tableId);
    }
    ttscommit;
}


If my memory isn’t failing me, this script works in AX4 – AX2012, but Axapta 3.0 doesn’t have changeTableId() a changeFieldId() methods in ReleaseUpdateDB and you have to implement them by yourself.
It is often forgotten that object IDs exist also in business data in database – one example is the ID of a table to which a document is attached. Ignoring this issue can affect database integrity, which is again felt by users as a data loss. One of possible solutions is to use my DataReferenceSearcher – although it actually doesn’t fix the found references, it helps you to write necessary data upgrade scripts.

How to using .net Regular Expression from Dynamics AX


static void THK_RegularExpression_Test()
{
    int         nameLen, numberLen;
    str         nameStr      = "Vasan2th";
    str         numberStr    = "1234";
    str         formatNumber, formatLetter;
    boolean     retName, retNumber;
    
    System.Text.RegularExpressions.Regex    regExLetter;
    System.Text.RegularExpressions.Regex    regExNumber;
    System.Text.RegularExpressions.Match    regMatch;
    
    InteropPermission   permission = new InteropPermission(InteropKind::ClrInterop);
;
    nameLen         = strLen(nameStr);
    numberLen       = strLen(numberStr);
    formatNumber    = strfmt(@"^[0-9]{%1}", numberLen);
    formatLetter    = strfmt(@"^[a-zA-Z ]{%1}", nameLen);
    permission.assert();
    
    //BP Deviation documented
    regExLetter = new System.Text.RegularExpressions.Regex(formatNumber);
    regMatch    = regExLetter.Match(numberStr);
    retNumber   = regMatch.get_Success();
    print "Is number format ,  ", retNumber; // Returns True;
    
    regExNumber = new System.Text.RegularExpressions.Regex(formatLetter);
    regMatch    = regExNumber.Match(nameStr);
    retName     = regMatch.get_Success();
    print "Is Letter format ,  ", retName; // Returns false;
    
    pause;
}

How to delete all transactions from AX 2012


How to delete all transactions from AX 2012. Previously we were using SysDatabaseTransDelete class to do the same but as of now we need to modify that class to work properly with AX 2012 due to DB changes :

We need to modify the SysDatabaseTransDelete.handletable method with the below code :

void handleTable(SysDictTable sysDictTable)
{
    TableGroup      tableGroup;

    if (tableSet.in(sysDictTable.id()))
        return;
    tableSet.add(sysDictTable.id());

    if (sysDictTable && !sysDictTable.isTmp() && !sysDictTable.isMap())
    {
        tableGroup = sysDictTable.tableGroup();

        // Handle company specific tables to be deleted
        if (sysDictTable.dataPrCompany())
        {
            switch(tableGroup)
            {
                case TableGroup::Transaction:
                case TableGroup::WorksheetHeader:
                case TableGroup::WorksheetLine:
                //FIX - Support new AX2012 transaction table types
                case TableGroup::TransactionHeader:
                case TableGroup::TransactionLine:
                    this.handleTransTable(sysDictTable);
                    break;
                default:
                    this.handleNonTransTable(sysDictTable);
                    break;
            }
        }
        else
        {
            // Handle global tables to be deleted
            switch(tableGroup)
            {
                case TableGroup::Transaction:
                case TableGroup::WorksheetHeader:
                case TableGroup::WorksheetLine:
                //FIX - Support new AX2012 transaction table types
                case TableGroup::TransactionHeader:
                case TableGroup::TransactionLine:
                    this.handleGlobalTransTable(sysDictTable);
                    break;
                default:
                    break;
            }
        }
    }
}

How to convert measurement from Char to MM on dyamics ax report




ReportControl 默认是100mm计量,传入参数Char2100mm(12)得到12 char的100mm长度值

reportControl.left100mm(Char2100mm(12,WidthHeight::Width));
reportControl.width100mm(Char2100mm(15,WidthHeight::Width));
reportControl.top100mm(Char2100mm(12,WidthHeight::Height));
reportControl.height100mm(Char2100mm(2,WidthHeight::Height));

所以增加以下方法可以用来计算Char和MM单位转换后的值。

public static real THK_Char2100mm(real          _measurement,
                                  WidthHeight   _WidthHeight)
{
    real    convertedMeasurement;
;
    if (_measurement)
    {
        switch (_WidthHeight)
        {
            case WidthHeight::Width :
                convertedMeasurement = _measurement *   161;
                break;

            case WidthHeight::Height :
                convertedMeasurement = _measurement *   361;
                break;
        }
    }
    else
    {
        convertedMeasurement = _measurement;
    }
    return convertedMeasurement;
}

How to achieved to copy data from origanl table instance to new table instance


One of the useful method from standard AX is the buf2Buf(), it behave similar to table's .data() method with one difference - buf2buf doesn't copy system field. Another reason of using buf2buf is copying of record from one company to another company. When using changeCompany(), the .data() method copy all field including DataAreaId and when insert(), DataAreaId field does not change, hence, the record is not inserted into the company indicated in the changeCompany(), here is where buf2Buf() comes in handy - copy all field except system field, then during insert(), let the system assign values to system field.

Sometimes, there're some functionality requires copy data from one table to another table which has similar structure (Eg. to history or logging table), in this case, the .data() and buf2Buf() cannot be used. But we can make some modification to the buf2Buf() method to copy based on field name instead of field Id.

Below are the two methods:
global::buf2Buf()  - Standard AX method
THK_buf2BufBySameFileldName()  - modified method

//Standard AX method, copy data based on field Id

1)global::buf2Buf

static void buf2Buf(
    Common  _from,
    Common  _to
    )
{
    DictTable   dictTable = new DictTable(_from.TableId);
    fieldId     fieldId   = dictTable.fieldNext(0);

    while (fieldId && ! isSysId(fieldId))
    {
        _to.(fieldId)   = _from.(fieldId);
        fieldId         = dictTable.fieldNext(fieldId);
    }
}


2)THK_buf2BufBySameFileldName
//Modified method, copy data from one table to another table with similar structure
// USR Changed on 29 十月 2012 at 11:35:14 by admin

static void THK_buf2BufBySameFileldName(Common  _from, Common  _to)
{
    DictTable   dictTableFrom   = new DictTable(_from.TableId);
    DictTable   dictTableTo     = new DictTable(_to.TableId);
    DictField   dictFieldFrom;
    FieldId     fieldIdFrom     = dictTableFrom.fieldNext(0);
    FieldId     fieldIdTo;
;
    while (fieldIdFrom && ! isSysId(fieldIdFrom))
    {
        dictFieldFrom   = new DictField(_from.TableId, fieldIdFrom);
        if(dictFieldFrom)
        {
            fieldIdTo = dictTableTo.fieldName2Id(dictFieldFrom.name());
            if(fieldIdTo)
                _to.(fieldIdTo) = _from.(fieldIdFrom);
        }
        fieldIdFrom = dictTableFrom.fieldNext(fieldIdFrom);
    }
}

2012年10月28日星期日

How to achieve save(put) and get Last Value on Form


1) Use pack/unpack on Form

If you have used runbase classes, you may be impressed by its pack and unpack mechanism. It allows users to keep the input values of last time. If you want to implement the same mechanism on the Form, it is easy as well:

Besides Pack/Unpack, add these six methods:


public class FormRun extends ObjectRun
{
    ...
    #define.CurrentVersion(1)
    #localmacro.CurrentList
        values...
    #endmacro
}

public container pack()
{
    return [#CurrentVersion, #CurrentList];
}

public boolean unpack(container packedClass)
{
    Integer version = conpeek(packedClass,1);

    switch (version)
    {
        case #CurrentVersion:
            [version,#CurrentList] = packedClass;
            break;
        default:
            return false;
    }
    return true;
}


public dataAreaId lastValueDataAreaId()
{
return curExt();
}

private UserId lastValueUserId()
{
return curuserid();
}
private UtilElementType lastValueType()
{
return UtilElementType::Form;
}
private IdentifierName lastValueElementName()
{
return this.name();
}
private IdentifierName lastValueDesignName()
{
return ;
}

//this is called when no last value is retrieved
void initParmDefault()
{
}

further, in Close method of the form:
public void close()
{
super();
//add saveLast method after super()
xSysLastValue::saveLast(this);
}

in init method of the form:
public void init()
{
;
    //Add getLast method before super()
xSysLastValue::getLast(this);
super();

}
2)Container lastValues;
get
 lastValues  = xSyslastValue::getValue(curext(), curUserId(), utilElementType::Form,element.name() + "out","");
put
xSyslastValue::putValue([JournalName],curext(), curUserId(), utilElementType::Form,element.name(),"");

How to using X++ code create and posting a ledger journal


Here is the adapted example for posting a ledger journal line. Simply replace values between #s (#value#):

static void ExampleLedgerJournal(Args _args)
{
    LedgerJournalTable      ledgerJournalTable;
    LedgerJournalTrans      ledgerJournalTrans;
    LedgerJournalCheckPost  ledgerJournalCheckPost;
    NumberSeq               numberSeq;
    ;

    ttsbegin;

    // Journal name
    ledgerJournalTable.JournalName = "#JOURNALNAME#"; // ex. Daily, daytrans, etc.
    ledgerJournalTable.initFromLedgerJournalName();
    ledgerJournalTable.Name = "#DESCRIPTION#";  // description for this journal
    ledgerJournalTable.insert();

    // Voucher
    numberSeq = NumberSeq::newGetVoucherFromCode(LedgerJournalName::find(ledgerJournalTable.JournalName).VoucherSeries);
    ledgerJournalTrans.Voucher = numberSeq.voucher();

    // Lines
    ledgerJournalTrans.JournalNum = ledgerJournalTable.JournalNum;
    ledgerJournalTrans.CurrencyCode = CompanyInfo::standardCurrency();
    ledgerJournalTrans.ExchRate = Currency::exchRate(ledgerJournalTrans.CurrencyCode);
    ledgerJournalTrans.AccountNum = "#ACCOUNT#";
    ledgerJournalTrans.AccountType = LedgerJournalACType::Ledger;
    ledgerJournalTrans.AmountCurDebit = #VALUE#;
    ledgerJournalTrans.TransDate = systemDateGet(); //Avoid the Today function
    ledgerJournalTrans.OffsetAccount = "#OFFSET ACCOUNT#";
    ledgerJournalTrans.Txt = "#TXT#";
    ledgerJournalTrans.insert();

    //Posting the Journal
    ledgerJournalCheckPost = LedgerJournalCheckPost::newLedgerJournalTable(ledgerJournalTable, NoYes::Yes);
    ledgerJournalCheckPost.run();
    
    ttscommit;
}

How to using X++ code to delete AOT nodes

1) TreeNode class
Sometimes, bad objects can not be removed from the AOT because when you click them, Axapta crush !! Look up this job:
static void DeleteDamnTables(Args _args)
{
    TreeNode edt, edt2;
    ;

    edt = TreeNode::findNode("Data Dictionary\\Tables");
    if (edt != null)
    {
        edt2 = edt.AOTfindChild("tablename");
        if (edt2 != null)
            edt2.AOTdelete();
    }
}
2) UtilIdElements solution
Warning: Serious problems might occur if you modify the UtilIdElements table using this or another method. Modify system tables at your own risk.

The code:

static void Job1(Args _args) 
{ 
    UtilIdElements utilElement; 
    ; 

    ttsbegin; 

    select utilElement 
        where utilElement.name == 'myElementName'
        && utilElement.utilLevel == utilEntryLevel::cus // any layer 
        && utilElement.recordType == utilElementType::Table; // object type 

    if (utilelement) 
    { 
        utilElement.delete(); 

        ttscommit; 
        info('Record should be deleted now.'); 
    } 
    else 
    { 
        ttsAbort; 
        info('Could not delete record, or it was not found.'); 
    } 
}

How to invoking to the caller Form/DataSource method


If we need to notify events to the caller form we can try this pattern:

In the child form, make a method named updateCaller and invoke it when you want to notify the parent:

void updateCaller()
{
    Common common;
    Object dataSource;
    Object caller;
    ;

    //-----------------------------------
    //We are notifying using the dataSource
    common = element.args().record();
    if (common
        && common.isFormDataSource()
        && formDataSourceHasMethod(common.dataSource(), identifierstr(SomethingWasHappend)))
    {
        dataSource = common.dataSource();
        dataSource.SomethingWasHappend();
    }
    //-----------------------------------

    //-----------------------------------
    //We are notifying using the form
    caller = element.args().caller();
    if (caller
        && classidget(caller) == classnum(SysSetupFormRun)
        && formHasMethod(caller, identifierstr(SomethingWasHappend)))
    {
        caller.SomethingWasHappend();
    }
    //-----------------------------------
}

Implement the handling method in the parent form:

void SomethingWasHappend()
{
    ;
    info("Something was happend (Form)");
}

Or if you prefer, in the DataSource:

void SomethingWasHappend()
{
    ;
    info("Something was happend (DataSource)");
}

Invoking it from a simple button inside the child form:

void clicked()
{
    super();

    element.updateCaller();
}


See a pratical sample in the form MarkupTrans (DataSource -> method write).

2012年10月19日星期五

How to using SQL statement directly execute to Dynamics AX


This is not a recommended approach to run query against AX, but sometimes there's a need for it (Eg. stored procedure), below is the sample code to run SQL statement directly to the AX database (you'll need to do manual security check due to this approach will skip AX security validation).

I usually has a class with 2 simple method:
  • executeUpdate
    Used to execute INSERT, UPDATE, DELETE statement
  • executeQuery
    Used to execute SELECT statement

//Class :: SQLUtility ==========================================
class SQLUtility
{
}

//Method :: executeUpdate ======================================
server static int executeUpdate(str sql, Connection connection = new Connection())
{
    SqlStatementExecutePermission   sqlPerm;
    Statement                       statement;
    int                             rowsAffected;
    ;

    if(sql)
    {
        sqlPerm = new SqlStatementExecutePermission(sql);
        sqlPerm.assert();

        statement    = connection.createStatement();

        rowsAffected = statement.executeUpdate(sql);

        CodeAccessPermission::revertAssert();
    }

    return rowsAffected;
}

//Method :: executeQuery =======================================
server static ResultSet executeQuery(str sql, Connection connection = new Connection())
{
    SqlStatementExecutePermission   sqlPerm;
    Statement                       statement;
    ResultSet                       resultSet;
    ;

    sqlPerm = new SqlStatementExecutePermission(sql);
    sqlPerm.assert();

    statement = connection.createStatement();
    resultSet = statement.executeQuery(sql);

    CodeAccessPermission::revertAssert();

    return resultSet;
}

//Job :: Job_DirectSQLTest =====================================
static void Job_DirectSQLTest(Args _args)
{
    ResultSet       testRS;
    ;
    
    testRS = SQLUtility::executeQuery("select top 10 ItemId from InventTable");
    while(testRS.next())
    {
        info(testRS.getString(1));
    }
}

Result of running the job " Job_DirectSQLTest  "