Suppose you have over a million users, and you want to perform some kind of mass update to some of them. One approach might be to use a dynamic query to retrieve the list of users in question. Once loaded into memory, you could loop through the list and update each user. However, with over a million users, the memory cost of such an operation would be too great. In general, retrieving large numbers of Service Builder entities using dynamic queries requires too much memory and time.
Liferay actionable dynamic queries solve this problem. Actionable dynamic queries use a pagination strategy to load only small numbers of entities into memory at a time and perform processing (i.e., perform an action) on each entity. So instead of trying to use a dynamic query to load a million users into memory and then perform some processing on each of them, a much better strategy is to use an actionable dynamic query. This way, you can still process your million users, but only small numbers are loaded into memory at a time.
Here’s how to use actionable dynamic query:
-
Get an
ActionableDynamicQuery
from your*LocalService
by invoking itsgetActionableDynamicQuery
method. -
Add query criteria and constraints, using the query’s
setAddCriteriaMethod
andsetAddOrderCriteriaMethod
methods. -
Set an action to perform on the matching entities, using
setPerformActionMethod
. -
Execute the action on each matching entity, by invoking the query’s
performActions
method.
This method from a sample portlet creates an actionable dynamic query, adds a query restriction and an action, and executes the query:
protected void massUpdate() {
ActionableDynamicQuery adq = _barLocalService.getActionableDynamicQuery();
adq.setAddCriteriaMethod(new ActionableDynamicQuery.AddCriteriaMethod() {
@Override
public void addCriteria(DynamicQuery dynamicQuery) {
dynamicQuery.add(RestrictionsFactoryUtil.lt("field3", 100));
}
});
adq.setPerformActionMethod(new ActionableDynamicQuery.PerformActionMethod<Bar>() {
@Override
public void performAction(Bar bar) {
int field3 = bar.getField3();
field3++;
bar.setField3(field3);
_barLocalService.updateBar(bar);
}
});
try {
adq.performActions();
}
catch (Exception e) {
e.printStackTrace();
}
}
The example method demonstrates executing an actionable dynamic query on Bar
entities that match certain criteria.
-
Retrieve an
ActionableDynamicQuery
from local serviceBarLocalService
.ActionableDynamicQuery adq = _barLocalService.getActionableDynamicQuery();
-
Set query criteria to match
field3
values less than100
.adq.setAddCriteriaMethod(new ActionableDynamicQuery.AddCriteriaMethod() { @Override public void addCriteria(DynamicQuery dynamicQuery) { dynamicQuery.add(RestrictionsFactoryUtil.lt("field3", 100)); } });
-
Set an action to perform. The action increments the matching entity’s
field3
value.adq.setPerformActionMethod(new ActionableDynamicQuery.PerformActionMethod<Bar>() { @Override public void performAction(Bar bar) { int field3 = bar.getField3(); field3++; bar.setField3(field3); _barLocalService.updateBar(bar); } });
-
Execute the action on each matching entity.
try { adq.performActions(); } catch (Exception e) { e.printStackTrace(); }
Actionable dynamic queries let you act on large numbers of entities in smaller groups. It’s an efficient and high performing way to update entities.