You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Replace fictional ABC Shoe Size example with real SalesForecastUpgrade.Codeunit.al
Port actual production code from microsoft/ALAppExtensions instead of invented tutorial
code. Source: Apps/W1/SalesAndInventoryForecast/app/src/codeunits/SalesForecastUpgrade.Codeunit.al
- Remove fictional Customer.Shoesize field migration (ABC-1234 invented tag)
- Add real codeunit 1851 Sales Forecast Upgrade with namespace Microsoft.Inventory.InventoryForecast
- Real tag MS-474737-SalesForecastCustomerConsent-20230607
- Real HasUpgradeTag double-check pattern (database-scope '' + per-company)
- Add explanation of key patterns observed in the real code
- Link to ReviewGLEntries Upgrade.Codeunit.al for DataTransfer bulk migration pattern
Copy file name to clipboardExpand all lines: dev-itpro/developer/devenv-upgrading-extensions.md
+35-50Lines changed: 35 additions & 50 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -241,85 +241,70 @@ The following steps provide the general pattern for using an upgrade tag on upgr
241
241
242
242
### Example
243
243
244
-
The following code is a simple example of an upgrade codeunit. For this example, the original extension extended the **Customer** table with a **Shoesize** field. In the new version of the extension, the **Shoesize** field has been removed ([ObsoleteState](properties/devenv-obsoletestate-property.md)=removed), and replaced by a new field **ABC - Customer Shoesize**. The upgrade code will copy data from **Shoesize** field to the **ABC - Customer Shoesize**. An upgrade tag ensures that code doesn't run more than once, and data isn't overwritten on future upgrades. The example also uses a separate codeunit to define the upgrade tag so that they aren't hard-coded, but within methods.
244
+
The following code is taken directly from the `Sales Forecast Upgrade` codeunit in `microsoft/ALAppExtensions`. It demonstrates the canonical upgrade tag pattern: check the tag first, run conditional data migration, then set the tag to prevent the code from running again on future upgrades.
245
+
246
+
> Source: [`SalesForecastUpgrade.Codeunit.al`](https://github.com/microsoft/ALAppExtensions/blob/main/Apps/W1/SalesAndInventoryForecast/app/src/codeunits/SalesForecastUpgrade.Codeunit.al) in `microsoft/ALAppExtensions`
245
247
246
248
```AL
247
-
namespace Contoso.ABCShoeExtension;
249
+
namespace Microsoft.Inventory.InventoryForecast;
248
250
249
-
using Microsoft.Sales.Customer;
251
+
using System.Threading;
250
252
using System.Upgrade;
251
253
252
-
codeunit 50100 "ABC Upgrade Shoe Size"
254
+
codeunit 1851 "Sales Forecast Upgrade"
253
255
{
254
256
Access = Internal;
255
257
Subtype = Upgrade;
256
258
257
259
trigger OnUpgradePerCompany()
258
260
var
259
-
ABCUpgradeTagDefinitions: Codeunit "ABC Upgrade Tag Definitions";
260
-
UpgradeTagMgt: Codeunit "Upgrade Tag";
261
+
ModuleInfo: ModuleInfo;
261
262
begin
262
-
263
-
// Check whether the tag has been used before, and if so, don't run upgrade code
264
-
if UpgradeTagMgt.HasUpgradeTag(ABCUpgradeTagDefinitions.GetABCShoeSizeUpgradeTag()) then
265
-
exit;
266
-
267
-
// Run upgrade code
268
-
UpgradeShoeSize();
269
-
270
-
// Insert the upgrade tag in table 9999 "Upgrade Tags" for future reference
> This pattern is used verbatim in production Microsoft extensions. For example, see [`SalesForecastUpgrade.Codeunit.al`](https://github.com/microsoft/ALAppExtensions/blob/main/Apps/W1/SalesAndInventoryForecast/app/src/codeunits/SalesForecastUpgrade.Codeunit.al) in `microsoft/ALAppExtensions` for a real-world upgrade codeunit with namespace declarations and upgrade tags.
300
+
Key points from this production example:
301
+
302
+
-`HasUpgradeTag` is called twice — once with an empty company string `''` (database-level scope) and once without (per-company scope). The double-check prevents re-execution across both scopes.
303
+
- The upgrade tag procedure returns `Code[250]`, matching the parameter type of `HasUpgradeTag` and `SetUpgradeTag` exactly.
304
+
-`Access = Internal` prevents external callers from triggering the upgrade codeunit directly.
305
+
-`NavApp.GetCurrentModuleInfo()` retrieves app metadata (including data version) to gate whether migration is needed.
306
+
307
+
For bulk field migration across large tables (for example, copying data from an obsolete field to a replacement field), use `DataTransfer` instead of row-by-row `Modify`. For a real-world example of `DataTransfer` combined with upgrade tags, see [`Upgrade.Codeunit.al`](https://github.com/microsoft/ALAppExtensions/blob/main/Apps/W1/ReviewGLEntries/app/src/codeunits/Upgrade.Codeunit.al) in the Review GL Entries extension.
323
308
324
309
## Protecting sensitive code from running during upgrade
0 commit comments