Updating Liferay DXP Service Builder Entity

If you are using Liferay DXP and Service Builder, then you would have come across the situation where the updates to entity does not reflect after the first service build. That is the service builder changes and the schema update reflects fine when the service is build and deployed for the first time in server, the subsequent updates to the service.xml to add new column, update column or data type, increase data length, or delete columns, etc. changes does not reflect or updates the schema when the service is build subsequently.

To resolve this some of you would have tried different manual steps like, deleting entries for your service directly from servicecomponent and release_ tables in database, undeploy the service module, or even drop the entity schema and then deploy the service again to overcome the issue.  This might not be an good option to try in the production. So, what is the correct way to approach this situation?

This blog is intended to help and share with others, facing similar challenges on how they can handle this through service builder upgrade process.

Service Builder Upgrade Process

Service Builder is a model-driven code generation tool built by Liferay that allows developers to define custom object models called entities. Service Builder generates a service layer through object-relational mapping (ORM) technology that provides a clean separation between your object model and code for the underlying database. At a brief there are following key steps that we perform,

  1. Create a Service builder module
  2. Create an Service Builder Entity Like Employee
  3. Build Service and Deploy

When we are changing the entities in service.xml and rebuild services, ServiceBuilder will update the SQL files used to create the tables, indices, etc. When you deploy the service the first time, ServiceBuilder will identify the initial deployment and will use the SQL files to create the entities and it will create the table in database.
But there are some cases where we need to update existing service builder entity in service.xml, like adding new column, changing column type, increasing column length, deleting column. In these cases, we can easily update in service.xml file and build service and deploy. But it will not update the table, for that we need to write an upgrade process for service builder.
Lets take an example by adding new column.

Adding New Column

  1. To add new column Like “Address” in existing service builder entity first update the new column name in service.xml and build the service.
  2. Create class “UpgradeEmployee.java” (You can give any name), extend the Liferay Upgrade Process and override doUpgrade method.

    public class UpgradeEmployee extends UpgradeProcess {

    private static final Log log = LogFactoryUtil.getLog(UpgradeEmployee.class);

    private static final String EMPLOYEE_NEW_COLUMN_NAME_ADDRESS = “address”;

    @Override
    protected void doUpgrade() throws Exception {
    log.info(“>>>>>> UPGRADE PROCESS FOR SERVICE BUILDER : START >>>>>>>”);

    /**
    * First Parameter Table Name
    * Second Parameter New Column Name
    */
    boolean isAddressColumnExist = hasColumn(EmployeeImpl.TABLE_NAME, EMPLOYEE_NEW_COLUMN_NAME_ADDRESS);
    log.info(“is Address Column Exist: ” + isAddressColumnExist);
    if (!isAddressColumnExist) {
    String addressColumnType = “STRING”;
    alter(EmployeeImpl.class, new AlterTableAddColumn(EMPLOYEE_NEW_COLUMN_NAME_ADDRESS + StringPool.SPACE + addressColumnType));
    }

    log.info(“>>>>>> UPGRADE PROCESS FOR SERVICE BUILDER : END >>>>>>>”);
    }
    }

  3. Add below dependency in service module build.gradle file

    compileOnly group: ‘com.liferay’, name: ‘com.liferay.portal.upgrade.api’

  4. Now Register the UpgradeEmployee using UpgradeStepRegistrator for that create “EmployeeServiceUpgrade” and implement the Liferay “UpgradeStepRegistrator” interface.

    @Component(
    immediate = true,
    service = UpgradeStepRegistrator.class
    )
    public class EmployeeServiceUpgrade implements UpgradeStepRegistrator {

    private static final Log log = LogFactoryUtil.getLog(EmployeeServiceUpgrade.class);
    @Override
    public void register(Registry registry) {
    log.info(“>>>>>>>>>>> Registering Employee Upgrade >>>>>>>>>>>”);
    /*
    * Old Schema Version 1.0.0 which is specified in bnd.bnd
    * New Schema Version 1.0.1
    */
    registry.register(“1.0.0”, “1.0.1”, new UpgradeEmployee());
    }
    }

  5. Update new Schema version in bnd.bnd file which we have specified in above class

    Liferay-Require-SchemaVersion: 1.0.1

  6. Now deploy the service, the new column should reflect in your database.

Dropping existing Column

  1. Remove Column name like “middleName” from Service.xml and build the service.
  2. Add below code in doUpgrade Method

    public class UpgradeEmployee extends UpgradeProcess {

    private static final Log log = LogFactoryUtil.getLog(UpgradeEmployee.class);

    private static final String EMPLOYEE_NEW_COLUMN_NAME_ADDRESS = “address”;

    private static final String EMPLOYEE_COLUMN_NAME_MIDDLE_NAME = “middleName”;

    @Override
    protected void doUpgrade() throws Exception {
    log.info(“>>>>>> UPGRADE PROCESS FOR SERVICE BUILDER : START >>>>>>>”);

    /**
    * First Parameter Table Name
    * Second Parameter New Column Name
    */
    boolean isAddressColumnExist = hasColumn(EmployeeImpl.TABLE_NAME, EMPLOYEE_NEW_COLUMN_NAME_ADDRESS);
    log.info(“is Address Column Exist : ” + isAddressColumnExist);
    if(!isAddressColumnExist) {
    String addressColumnType = “VARCHAR(200)”;
    alter(EmployeeImpl.class, new AlterTableAddColumn(EMPLOYEE_NEW_COLUMN_NAME_ADDRESS + StringPool.SPACE + addressColumnType));
    }

    boolean isMiddleNameExist = hasColumn(EmployeeImpl.TABLE_NAME, EMPLOYEE_COLUMN_NAME_MIDDLE_NAME);
    log.info(“is Middle Name Column Exist : ” + isMiddleNameExist);
    if(isMiddleNameExist) {
    alter(EmployeeImpl.class, new AlterTableDropColumn(EMPLOYEE_COLUMN_NAME_MIDDLE_NAME));
    }

    log.info(“>>>>>> UPGRADE PROCESS FOR SERVICE BUILDER : END >>>>>>>”);
    }
    }

  3. Update New Schema Version in bnd.bnd and EmployeeServiceUpgrade class.

    Note: If you have already created EmployeeServiceUpgrade class then do not create again just update schema version

    @Component(
    immediate = true,
    service = UpgradeStepRegistrator.class
    )
    public class EmployeeServiceUpgrade implements UpgradeStepRegistrator {

    private static final Log log = LogFactoryUtil.getLog(EmployeeServiceUpgrade.class);
    @Override
    public void register(Registry registry) {
    log.info(“>>>>>>>>>>> Registering Employee Upgrade >>>>>>>>>>>”);
    /*
    * Old Schema Version 1.0.1 which is specified in bnd.bnd
    * New Schema Version 1.0.2
    */
    registry.register(“1.0.1”, “1.0.2”, new UpgradeEmployee());
    }
    }

  4. Update Liferay-Require-SchemaVersion in bnd.bnd
    Liferay-Require-SchemaVersion: 1.0.2
  5. Deploy Service Builder Module
  6. Now deploy the service, the existing column should be dropped from your database.

Updating Column Name and Data Size

If you want to change column name “username” to “modifiedBy” with type VARCHAR(100) from VARCHAR(75).

  1. Follow the same step as above and add below code in doUpgrade method

    // Change Column Type with Column Name
    boolean isUserNameColumnExist = hasColumn(EmployeeImpl.TABLE_NAME, “userName”);
    log.info(“is UserName Column Exist : ” + isUserNameColumnExist);
    if(isUserNameColumnExist) {
    alter(EmployeeImpl.class, new AlterColumnName(“userName”,”modifiedBy VARCHAR(100)”));

    }

  2. Similarly update schema version in bnd.bnd as well as EmployeeServiceUpgrade class.
  3. Deploy the service
  4. Now deploy the service, the column name and data type update should reflect in your database.

Adding New Entity in Service Builder

Sometime table is not created once service is deployed for that as well, we need to write Upgrade process.

  1. Add new Entity Like “LeaveRequest” in existing service builder
  2. Build Service.
  3. Same as above Create class “UpgradeEmployee.java” extend the Liferay Upgrade Process and override doUpgrade method.

    public class UpgradeEmployee extends UpgradeProcess {
    private static final Log log = LogFactoryUtil.getLog(UpgradeEmployee.class);

    @Override
    protected void doUpgrade() throws Exception {
    log.info(“>>>>>> UPGRADE PROCESS FOR SERVICE BUILDER : START >>>>>>>”);
    boolean isLeaveRequestTableExist = hasTable(LeaveRequestImpl.TABLE_NAME);
    log.info(“is Leave Request Table Exist : ” +  isLeaveRequestTableExist);
    if(!isLeaveRequestTableExist) {
    runSQL(LeaveRequestImpl.TABLE_SQL_CREATE);
    }
    log.info(“>>>>>> UPGRADE PROCESS FOR SERVICE BUILDER : END >>>>>>>”);
    }
    }

  4. Now Register the UpgradeEmployee using UpgradeStepRegistrator for that create “EmployeeServiceUpgrade” and implement the Liferay “UpgradeStepRegistrator” interface.(Same as above)Note: If you have already created EmployeeServiceUpgrade class then do not create again just update schema version

    @Component(
    immediate = true,
    service = UpgradeStepRegistrator.class
    )
    public class EmployeeServiceUpgrade implements UpgradeStepRegistrator {

    private static final Log log = LogFactoryUtil.getLog(EmployeeServiceUpgrade.class);
    @Override
    public void register(Registry registry) {
    log.info(“>>>>>>>>>>> Registering Employee Upgrade >>>>>>>>>>>”);
    /*
    * Old Schema Version 1.0.3 which is specified in bnd.bnd
    * New Schema Version 1.0.4
    */
    registry.register(“1.0.3”, “1.0.4“, new UpgradeEmployee());
    }
    }

  5. Update new Schema version in bnd.bnd file which we have specified in above class
    Liferay-Require-SchemaVersion: 1.0.4
  6. Deploy the service builder module. Table will be created after deploying.
  7. Now deploy the service, the new table schema will be created in your database.
abc
Scroll to more