Business Central 2022 wave 2 (BC21) new features: Developers can write faster upgrade code (New DataTransfer data type)

Dynamics 365 Business Central

Hi, Readers.
The preview environment for Dynamics 365 Business Central 2022 release wave 2 (BC21) is available. Learn more: Link.

I will continue to test and share some new features that I hope will be helpful.

Developers can write faster upgrade code:

Business value:

Using a new language construct, developers can write faster upgrade code when they want to move a field (with data) from one table to another or when they want to copy all data from one table to another.

Feature details:

When refactoring an app, it’s common to move a field from one table to another or to copy all data from one table to another table. With this feature, the developer can copy the data from the old field to the new field, or copy the data from the old table to the new table, in a set-based manner without the need to write a loop.

This makes writing upgrade code significantly faster.

https://docs.microsoft.com/en-us/dynamics365-release-plan/2022wave2/smb/dynamics365-business-central/performance–developers-write-faster-upgrade-code

Microsoft has not given details about this feature at the moment. But fortunately, I saw clues of this feature on Twitter two days ago. (Thanks a lot for sharing the information👏)

In Business Central 2022 wave 2 (BC21) (“runtime”: “10.0”), we can create a new data type, DataTransfer data type. (Only for upgrade codeunit)

Here is a standard example of moving obsoleted fields in same table, Database::”Purchase Line”.
Codeunit 104021 “Upgrade Item Cross Reference”:

Source Code:

    local procedure UpgradePurchaseLine()
    var
        PurchaseLine: Record "Purchase Line";
        PurchaseLineDataTransfer: DataTransfer;
    begin
        PurchaseLine.SetFilter("Item Reference No.", '<>%1', '');
        if not PurchaseLine.IsEmpty() then
            exit;

        // Move obsoleted fields
        PurchaseLineDataTransfer.SetTables(Database::"Purchase Line", Database::"Purchase Line");
        PurchaseLineDataTransfer.AddSourceFilter(PurchaseLine.FieldNo("Cross-Reference No."), '<>%1', '');
        PurchaseLineDataTransfer.AddFieldValue(PurchaseLine.FieldNo("Cross-Reference No."), PurchaseLine.FieldNo("Item Reference No."));
        PurchaseLineDataTransfer.AddFieldValue(PurchaseLine.FieldNo("Cross-Reference Type"), PurchaseLine.FieldNo("Item Reference Type"));
        PurchaseLineDataTransfer.AddFieldValue(PurchaseLine.FieldNo("Cross-Reference Type No."), PurchaseLine.FieldNo("Item Reference Type No."));
        PurchaseLineDataTransfer.AddFieldValue(PurchaseLine.FieldNo("Unit of Measure (Cross Ref.)"), PurchaseLine.FieldNo("Item Reference Unit of Measure"));
        PurchaseLineDataTransfer.UpdateAuditFields := false;
        PurchaseLineDataTransfer.CopyFields();

        // Move IC Partner Reference
        Clear(PurchaseLineDataTransfer);
        PurchaseLineDataTransfer.SetTables(Database::"Purchase Line", Database::"Purchase Line");
        PurchaseLineDataTransfer.AddSourceFilter(PurchaseLine.FieldNo("Cross-Reference No."), '<>%1', '');
        PurchaseLineDataTransfer.AddSourceFilter(PurchaseLine.FieldNo("IC Partner Ref. Type"), '=%1', PurchaseLine."IC Partner Ref. Type"::"Cross Reference");
        PurchaseLineDataTransfer.AddFieldValue(PurchaseLine.FieldNo("IC Partner Reference"), PurchaseLine.FieldNo("IC Item Reference No."));
        PurchaseLineDataTransfer.UpdateAuditFields := false;
        PurchaseLineDataTransfer.CopyFields();
    end;

And another example of moving data from different tables, Database::”Dimension” and Database::”Dimension Value”.
codeunit 104000 “Upgrade – BaseApp”:

Source Code:

    local procedure UpgradeDimensionValues()
    var
        Dimension: Record "Dimension";
        DimensionValue: Record "Dimension Value";
        UpgradeTagDefinitions: Codeunit "Upgrade Tag Definitions";
        UpgradeTag: Codeunit "Upgrade Tag";
        BlankGuid: Guid;
        DimensionValueDataTransfer: DataTransfer;
    begin
        if UpgradeTag.HasUpgradeTag(UpgradeTagDefinitions.GetDimensionValueDimensionIdUpgradeTag()) then
            exit;

        DimensionValue.SetFilter("Dimension Id", '<>%1', BlankGuid);
        if DimensionValue.IsEmpty() then begin
            DimensionValueDataTransfer.SetTables(Database::"Dimension", Database::"Dimension Value");
            DimensionValueDataTransfer.AddFieldValue(Dimension.FieldNo(SystemId), DimensionValue.FieldNo("Dimension Id"));
            DimensionValueDataTransfer.AddJoin(Dimension.FieldNo(Code), DimensionValue.FieldNo("Dimension Code"));
            DimensionValueDataTransfer.UpdateAuditFields := false;
            DimensionValueDataTransfer.CopyFields();
        end;

        UpgradeTag.SetUpgradeTag(UpgradeTagDefinitions.GetDimensionValueDimensionIdUpgradeTag());
    end;

So, the above are two basic patterns. We no longer need a write loop to copy data. And this is much more faster.
Next, let’s see what methods are available on the DataTransfer data type.

DataTransfer.AddConstantValue(): procedure AddConstantValue(Value: Joker, DestinationField: Integer)

Specifies the given value is to be set in the given field in the destination table.

DataTransfer.AddFieldValue(): procedure AddFieldValue(SourceField: Integer, DestinationField: Integer)

Specifies a source and destination field, where the values from the source field are to be copied to the destination field. The data types of the fields must match, except CODE to TEXT which is allowed.

DataTransfer.AddJoin(): procedure AddJoin(SourceField: Integer, DestinationField: Integer)

Adds a field pair to be used to create a join condition which determines which rows to transfer, optional for same table transfers.

DataTransfer.AddSourceFilter(): procedure AddSourceFilter(SourceField: Integer, String: Text, [Value: Joker, …])

Adds a filter for the source table for the data transfer.

DataTransfer.CopyFields(): procedure CopyFields()

Copies the fields specified in AddFields with filters from AddSourceFilter, and the join conditions from AddJoins in one bulk operation in SQL.

DataTransfer.CopyRows(): procedure CopyRows()

Copies the rows from the source table to the destination table with the fields selected with AddFields and the filters applied with AddSourceFilter, in one bulk operation in SQL.

DataTransfer.SetTables(): procedure SetTables(SourceTable: Integer, DestinationTable: Integer)

Sets the source and destination tables for the data transfer.

DataTransfer.UpdateAuditFields(): procedure UpdateAuditFields([UpdateAuditFields: Boolean]): Boolean

Sets if audit fields should be updated. If the value is set to false, the audit fields are not updated when calling the CopyFields method. Default value is true.

Note:
1. If you try to use the DataTransfer data type other than in Upgrade Codeunit, the following error will be prompted.

DataTransfer is only usable during upgrade code.

2. Only ‘Normal’ fields that are enabled, not a system field, not an audit field, or not part of the primary key are valid destination fields.

[2022-09-07 14:56:47.17] The request for path /v2.0/BC21US/dev/apps?SchemaUpdateMode=synchronize&DependencyPublishingOption=default failed with code UnprocessableEntity. Reason: Could not upgrade the extension ‘BC21Test’ by ‘YUN ZHU’ from version ‘1.0.0.0’ to ‘1.0.0.1’ for tenant ‘msft1a6720t59288419’ and company ‘CRONUS USA, Inc.’ due to the following error: ‘Field: ‘No.’ is not supported as a destination field for data transfer. Only ‘Normal’ fields that are enabled, not a system field, not an audit field, or not part of the primary key are valid destination fields.’ and AL stack trace: MyCodeunit(CodeUnit 50111).UpgradeLabBook line 18 – BC21Test by YUN ZHU MyCodeunit(CodeUnit 50111).OnUpgradePerCompany line 2 – BC21Test by YUN ZHU “Upgrade Triggers”(CodeUnit 2000000008).OnUpgradePerCompany(Event) line 2

3. Data transfers between different tables must specify a join condition.

[2022-09-07 14:59:20.36] The request for path /v2.0/BC21US/dev/apps?SchemaUpdateMode=synchronize&DependencyPublishingOption=default failed with code UnprocessableEntity. Reason: Could not upgrade the extension ‘BC21Test’ by ‘YUN ZHU’ from version ‘1.0.0.0’ to ‘1.0.0.1’ for tenant ‘msft1a6720t59288419’ and company ‘CRONUS USA, Inc.’ due to the following error: ‘Data transfers between different tables must specify a join condition.’ and AL stack trace: MyCodeunit(CodeUnit 50111).UpgradeLabBook line 18 – BC21Test by YUN ZHU MyCodeunit(CodeUnit 50111).OnUpgradePerCompany line 2 – BC21Test by YUN ZHU “Upgrade Triggers”(CodeUnit 2000000008).OnUpgradePerCompany(Event) line 2

4. The public preview of this feature is next month (Oct 2022), and please note that some features may not be available right now.

I will add some updates when Microsoft updates more information. Give it a try!!!😁

PS: Stefano Demiliani also posted a great blog yesterday to explain how to use DataTransfer data type, so you can check out his blog if you’re not sure what’s going on.
More details: Dynamics 365 Business Central 2022 Wave 2: introducing the new DataTransfer data type

Update from Business Central Launch Event (2022 release wave 2) 

Update: Transferring Data Between Tables using DataTransfer

Copying the SystemID and data audit fields using CopyRows is supported in Business Central version 21.5 and later.

END

Hope this will help.

Thanks for reading.

ZHU

コメント

Copied title and URL