How to: Write Extension Upgrade Code

Note

Extensions v1.0 are no longer supported. The text in the article applies to extensions v1.0. For information about writing extensions in AL, see the table below.

For information about See
Getting started writing extensions using the AL Language. Getting Started
Converting extensions. Converting Extensions V1 to Extensions V2
Writing extension install code for when an extension is installed for the first time, or for when an uninstalled extension is reinstalled. Writing Extension Install Code
Making a newer version of an extension available. Upgrading Extensions V2
Publishing, synchronizing, and installing the extension on the tenant. Publishing and Installing an Extension v2.0

The process of upgrading an extension includes uninstalling the current version of the extension and then installing a new version. If the extension modifies the schema of an existing table, or adds new tables, upgrade code will be required to handle the data that was automatically archived from the tables during uninstall. For more information about upgrading extensions, see Upgrading Extensions.

To write upgrade code for an extension

  1. Create new codeunit.

    Important

    This must be a codeunit of type Normal, not an Upgrade codeunit. For more information, see SubType Property.

  2. Add upgrade functions to the codeunit. Make sure the function is declared as global so that the Local property is set to No.

    1. Add the OnNavAppUpgradePerDatabase() function if the extension contains cross-company tables.
    2. Add the OnNavAppUpgradePerCompany() function if the extension contains per-company tables.
  3. Add the upgrade code to the appropriate function.

    The upgrade code will depend on what you want to do with the archived data, plus additional factors such as the version of the archive data, whether the schema has changed, and whether the data can be modified by users. Determine which of the following upgrade methods is required for each new or modified table in your extension. For more information, see the next sections.

Restore Table Data

If the table has the same schema as the archive data and doesn’t require any special upgrade logic, then use the RESTOREARCHIVEDATA system function to copy the archived data to the table. The data that is copied may be for new tables added as part of the extension or for fields added to existing base tables.

The following code example restores the archived data for tables 50000 and 50001 on a company basis.

PROCEDURE OnNavAppUpgradePerCompany@1();  
BEGIN  
  NAVAPP.RESTOREARCHIVEDATA(50000);  
  NAVAPP.RESTOREARCHIVEDATA(50001);  
END;  

Delete Table Data

If you do not want to restore the archived data to the table, then use the DELETEARCHIVEDATA system function to delete the archived data.

The following code deletes the archived data for table 50002 on a company basis.

PROCEDURE OnNavAppUpgradePerCompany@1();  
BEGIN  
  NAVAPP.DELETEARCHIVEDATA(50002);  
END;  

Upgrade Table Data

If the archived data is from a previous version and requires special upgrade logic, then use custom code to upgrade the records retrieved from the archive tables. For this scenario, you will use the following system functions:

The following code upgrades records that are retrieves from the archived table for table 50003. The upgrade code that is run depends on the extension version number of the archived data.

VAR
  ArchiveRecRef@1000 : RecordRef;  
  FldRef@1001 : FieldRef;  
  DestRec@1002 : Record;  
  Version@1003 : Text[20];  
PROCEDURE OnNavAppUpgradePerCompany@1();  
BEGIN  
  Version := NAVAPP.GETARCHIVEVERSION();  
  IF Version < '2.0.0.0' THEN BEGIN  
    // The Version 1 to Version 2 upgrade code block. Copy over relevant old fields and initialize new fields using archive data.  
    IF NAVAPP.GETARCHIVERECORDREF(50003, ArchiveRecRef) THEN BEGIN  
      IF ArchiveRecRef.FINDSET(FALSE) THEN BEGIN  
        DestRec.INIT;  
        REPEAT  
          FldRef := ArchiveRecRef.FIELD(50000);  
          DestRec.Key := FldRef.VALUE;  
          FldRef := ArchiveRecRef.FIELD(50001);  
          DestRec.V1Field := FldRef.VALUE;  
          DestRec.V2Field := 'NEW FIELD DEFAULT VALUE';  
          DestRec.INSERT;  
        UNTIL ArchiveRecRef.NEXT = 0;  
      END  
    END  
  END  
  ELSE BEGIN  
    // This is the reinstall (version 2 to version 2) block.  
    // Because the schema is the same for all minor versions of the version 2 product,  
    // you can copy the data in without changes.  
    NAVAPP.RESTOREARCHIVEDATA(50003);  
  END  
END;  

Note

The preceding sample code uses a strongly typed instance of the record for the destination. The other option is to use a RecordRef for both the source and destination. The sample code also assumes that any version 2 build of the extension uses the same table schema. If this is not true for your extension, you may have to use more specific version checks.

Tip

It is a best practice to use the IF NAVAPP.GETARCHIVERECORDREF(50003, ArchiveRecRef) THEN BEGIN construct to catch any exception that is thrown, for example, if a non-valid table was passed.

Load Default or Starting Table Data

If the table should always be populated with starting or default data that was included in the package, then use the NAVAPP.LOADPACKAGEDATA(TableNo) function to import the starting data to the table. If starting data is imported, then any archived data for the table will be deleted and not restored.

The following code example shows how to populate table 50004 with data.

PROCEDURE OnNavAppUpgradePerDatabase@1();
    BEGIN
        NAVAPP.LOADPACKAGEDATA(50004);
    END;

Conditional Restore or Load Starting Table Data

In some situations, you may want to conditionally use different options. For example, say that if archive data exists for a new extension table, you want to restore that data. But if archive data doesn’t exist, you want to import starting data from the package. In this scenario you will want to check for the existence of an archive table using the NAVAPP.GETARCHIVERECORDREF(TableNo) function and if a RecordRef is returned then restore or upgrade the table. If a record isn’t returned, then use the function to import the starting data for the table.

Sample Code:

PROCEDURE OnNavAppUpgradePerDatabase@1();
    // Variables:
    // ArchiveRecRef    RecordRef       
    BEGIN
      IF NAVAPP.GETARCHIVERECORDREF(50001, ArchiveRecRef) THEN
            NAVAPP.RESTOREARCHIVEDATA(50001)
        ELSE
                  NAVAPP.LOADPACKAGEDATA(50001);
    END;

See Also

Getting Started