IBMDO YOU?Hi, I'm MBO!

Settings

Make the site feel at home on your screen.

Theme

Loading your theme preference.

Keyboard shortcuts

Open search from anywhere, then move through the results without leaving the keyboard.

Open settings
Ctrl,or⌘,
Open search
CtrlKor⌘K
Select a search result
↑↓
Open the selected result
Enter
Close an open dialog
Esc

I Build Maximo

Understand MboSet count() in Maximo

Choose the right MboSet count mode and avoid turning a simple Maximo customization into repeated database queries.

MboSet.count() looks harmless, but it can be an expensive way to answer a simple question. The method can query the database each time it is called, so where you call it matters just as much as which count mode you choose.

This article explains the five count modes, what happens to added and deleted records, and how to avoid repeated count queries in Java customizations and automation scripts.

Start with the database cost

IBM's automation-script guidance is explicit: calling count() fires SQL every time. Do not put it in a loop condition or repeatedly call it for the same set. If you need the value more than once, calculate it once and store the result.

This becomes especially costly when an object initialization script calculates a related-record count. Imagine a relationship from WORKORDER to PRLINE named PRLINES, with this clause:

REFWO = :WONUM
AND SITEID = :SITEID
AND ORGID = :ORGID

If an initialization script calls getMboSet("PRLINES").count() to populate a nonpersistent field, opening a list of 100 work orders can generate a separate count query for every row. That is an N+1 query pattern, and every user opening a large result set can add more load.

Avoid calculating values like this during object initialization. Calculate them only when the user needs them, use an aggregate query designed for the list, or reconsider whether the count belongs on the list tab at all.

A planned-material validation has a different shape. An add script on WPMATERIAL already has access to its owning set, but that does not make repeated calls to count() free. Calculate the count once. If the code is already going to process every record, iterate through the set instead of running a separate count query first.

The count modes

Calling count() with no argument is the same as calling count(MboConstants.COUNT_EXISTING).

Mode Value What it counts
COUNT_DATABASE 1 Records that currently exist in the database. Unsaved additions are excluded, while database records marked for deletion still exist and are included.
COUNT_ADDITIONS 2 Records added to the set but not yet saved. This includes an added record that was subsequently marked for deletion.
COUNT_DELETED 4 Records marked for deletion, including database records and newly added records marked for deletion.
COUNT_EXISTING 8 Database records plus unsaved additions. This is the mode used by count().
COUNT_AFTERSAVE 16 The expected database total after save: database records plus additions, minus deletions.

Use the named constants so the intention remains obvious:

import psdi.mbo.MboConstants;
 
int existingCount = myMboSet.count();
int databaseCount = myMboSet.count(MboConstants.COUNT_DATABASE);
int additionCount = myMboSet.count(MboConstants.COUNT_ADDITIONS);
int deletedCount = myMboSet.count(MboConstants.COUNT_DELETED);
int afterSaveCount = myMboSet.count(MboConstants.COUNT_AFTERSAVE);

The constants have numeric values, but code such as myMboSet.count(16) makes the next person remember what 16 means. MboConstants.COUNT_AFTERSAVE documents the decision at the call site.

COUNT_DATABASE

Use this when the question is specifically, “How many matching rows are stored right now?” It ignores records added during the current transaction. A database row marked for deletion is still counted because the delete has not yet been saved.

COUNT_ADDITIONS

This counts unsaved additions. A new record is still an addition if a user adds it and then marks it for deletion before saving, so this value alone does not describe the eventual database state.

COUNT_DELETED

This counts records currently marked for deletion. That includes persisted records and unsaved additions that were later marked for deletion.

COUNT_EXISTING and count()

This is the database count plus unsaved additions. It does not subtract records marked for deletion, which is why it can differ from the number expected after the transaction is saved.

COUNT_AFTERSAVE

Use this when a validation rule needs the expected number of records after the current transaction commits. Conceptually, it is:

database records + additions - deletions

getSize() is not a replacement for count()

getSize() reports the current size of the collection loaded into memory. That can be useful when the code deliberately cares only about the records already fetched, but it is not a reliable total for every row matching the relationship in the database. A partially fetched set can therefore have a different getSize() and count() result.

Choose the method from the question you need to answer. Do not replace count() with getSize() purely to remove a query unless the loaded collection size is genuinely the required value.

Keep count calls under control

  • Store a count in a variable when it is used more than once.
  • Do not call count() in a for or while condition.
  • When processing the records anyway, iterate with the MBO APIs instead of counting first.
  • Avoid related-set counts from object initialization and list-tab rendering.
  • Close MBO sets created directly through MXServer, ideally in a finally block. Do not close sets owned by another MBO.
  • Treat BMXAA10026W as a prompt to inspect the script and its query pattern rather than merely suppressing the warning.

For a change involving unsaved records, test all four transaction states in a nonproduction environment: an existing record, a new record, an existing record marked for deletion, and a new record marked for deletion. Enable SQL logging briefly if necessary to verify how often the count query runs, then turn the extra logging back off.

References

Find the fix

Search articles

Esc

Search titles, technical terms or error codes.