Loading and Saving Data using Model Persistence
The purpose of this page is to help you become familiar with how iDempiere loads, modifies and saves data programmatically. In this tutorial, I am using iDempiere's "Create PO from Requisition" process as an example. You can execute this process from iDempiere's main menu when logged in as the GardenWorld Admin user.
General Common Examples
Here are persistence examples of common tasks from Create PO from Requisition:
- Finding and loading a record from a Record_ID using the old way (see below for newer better way): Line 148
- Creating a new record: Line 347
- Using iDempiere's Query class to find records: Lines 254 and 495
- Saving a record: Line 317
MTable.get() Example
There is a newer/better way to load models; however, this technique is not widely adopted yet. Therefore, you will not see it as often. The biggest benefit of this technique is that it respects IModelFactory. Said another way, using this method allows users to inject their own model and any call using this method will pick up the new/appropriate class. Example:
MTable table = MTable.get(Env.getCtx(), m_Some_AD_Table); PO po = table.getPO(id, null);
More practical example:
MDistributionRunLine drl = (MDistributionRunLine) MTable.get(getCtx(), MDistributionRunLine.Table_ID).getPO(record.getM_DistributionRunLine_ID(), get_TrxName());
To find more examples, right-click => References on MTable.getPO(...) method.
Every generated model has the X_... class. In it, it has getter methods that return an object instead of an ID. These methods give you an example of how to craft the statement. Here is an example:
public org.compiere.model.I_AD_Table getAD_Table() throws RuntimeException
{
return (org.compiere.model.I_AD_Table)MTable.get(getCtx(), org.compiere.model.I_AD_Table.Table_Name).getPO(getAD_Table_ID(), get_TrxName());
}
DB Example
Another important concept not demonstrated in the above process is using the DB class convenience methods. These methods help you use persistence best practices and simplify code at the same time. The MOrder class is full of examples:
- DB.getSQLValueEx(...)
- DB.executeUpdateEx(...)
One common question is "what does the Ex suffix at the end of DB.java methods mean?". Generally speaking, when you have two methods that are the same except where one ends in an Ex, the use the method with the Ex. These methods give you additional options for exception handling.
Transaction Management and Timeouts
When executing long-running processes, it is important to commit as often as it possible and appropriate. Try to avoid long-running, uncommitted processes.
Note the default timeout in iDempiere is 2 hours. Based on experience, the timeout is between commits. Said another way, if you are committing your transaction every could of minutes, your transaction can last for many hours
Here is an example of how you modify the transaction timeout:
Trx trx = Trx.get(get_TrxName(), false); trx.setTimeout(60 * 60 * 5); //about 5 hour