Use a Groovy script Action triggered by onAfterAdd or onAfterUpdate on the child object to update the parent object.
Here are two example Groovy scripts.
In the first one there is a text field 'sometext' in the parent object and its value is getting updated, every time a new child instance is created. Parent and Child objects have a one to many relationship.
In the second one there is an integer field 'numberofchildren' in the parent object and its value is getting incremented every time a new child instance is created.
1. Updating a text field in the parent object:
import com.liferay.portal.kernel.log.LogFactoryUtil
import com.liferay.portal.kernel.log.Log
import com.liferay.portal.kernel.service.ServiceContext
import com.liferay.object.model.ObjectEntry
import com.liferay.object.service.ObjectEntryLocalServiceUtil
import java.io.Serializable
Log log = LogFactoryUtil.getLog(this.class)
try {
log.info("Starting Parent update on Child creation...")
// Extract values from entryDTO["properties"]
Map<String, Object> properties = (Map<String, Object>) entryDTO.get("properties")
if (properties == null) {
log.error("No properties found in entryDTO!")
return
}
// Convert Parent ID to long
long parentEntryId = Long.parseLong((String) properties.get("r_relation_c_parentId"))
String childName = (String) properties.get("name")
log.info("Extracted Parent ID: " + parentEntryId)
log.info("Extracted Child Name: " + childName)
if (parentEntryId <= 0) {
log.error("Parent ID is invalid or missing!")
return
}
// Fetch the Parent entry
ObjectEntry parentEntry = ObjectEntryLocalServiceUtil.getObjectEntry(parentEntryId)
if (parentEntry == null) {
log.error("Parent entry not found for ID: " + parentEntryId)
return
}
log.info("Listing all Parent object fields...")
parentEntry.getValues().each { key, value ->
log.info("Field: " + key + " -> Value: " + value)
}
log.info("Parent entry found. Updating 'sometext' field...")
// Use the correct field key
String parentNameFieldKey = "sometext"
// Prepare updated values
Map<String, Serializable> values = new HashMap<>()
values.put(parentNameFieldKey, "Updated by Child: " + childName)
// Get user ID from `currentUserId`
long userId = (long) currentUserId
// Update the Parent object
ServiceContext serviceContext = new ServiceContext()
ObjectEntryLocalServiceUtil.updateObjectEntry(userId, parentEntryId, values, serviceContext)
log.info("Parent 'sometext' field update submitted successfully!")
} catch (Exception e) {
log.error("Script failed: " + e.getMessage(), e)
}
2. Updating an integer field in the parent object:
import com.liferay.portal.kernel.log.LogFactoryUtil
import com.liferay.portal.kernel.log.Log
import com.liferay.portal.kernel.service.ServiceContext
import com.liferay.object.model.ObjectEntry
import com.liferay.object.service.ObjectEntryLocalServiceUtil
import java.io.Serializable
Log log = LogFactoryUtil.getLog(this.class)
try {
log.info("Starting Parent numeric field update on Child creation...")
// Extract values from entryDTO["properties"]
Map<String, Object> properties = (Map<String, Object>) entryDTO.get("properties")
if (properties == null) {
log.error("No properties found in entryDTO!")
return
}
// Convert Parent ID to long
long parentEntryId = Long.parseLong((String) properties.get("r_relation_c_parentId"))
log.info("Extracted Parent ID: " + parentEntryId)
if (parentEntryId <= 0) {
log.error("Parent ID is invalid or missing!")
return
}
// Fetch the Parent entry
ObjectEntry parentEntry = ObjectEntryLocalServiceUtil.getObjectEntry(parentEntryId)
if (parentEntry == null) {
log.error("Parent entry not found for ID: " + parentEntryId)
return
}
log.info("Parent entry found. Fetching current numeric field value...")
// Define the numeric field key (replace with the actual field name)
String parentNumericFieldKey = "numberofchildren" // Replace with the actual numeric field name
// Get the current value and ensure it's a number
Object currentValue = parentEntry.getValues().get(parentNumericFieldKey)
int newValue = 0
if (currentValue instanceof Number) {
int currentIntValue = ((Number) currentValue).intValue()
// Check for overflow before incrementing
if (currentIntValue < Integer.MAX_VALUE) {
newValue = currentIntValue + 1
} else {
log.warn("Integer field overflow: current value is already at max.")
newValue = Integer.MAX_VALUE // Set to max value to avoid overflow
}
} else {
newValue = 1 // Start at 1 if the field is null or non-numeric
}
log.info("Current Value: " + currentValue + ", New Value: " + newValue)
// Prepare updated values
Map<String, Serializable> values = new HashMap<>()
values.put(parentNumericFieldKey, newValue)
// Get user ID from `currentUserId`
long userId = (long) currentUserId
// Update the Parent object
ServiceContext serviceContext = new ServiceContext()
ObjectEntryLocalServiceUtil.updateObjectEntry(userId, parentEntryId, values, serviceContext)
log.info("Parent numeric field '" + parentNumericFieldKey + "' updated successfully!")
} catch (Exception e) {
log.error("Script failed: " + e.getMessage(), e)
}