Clarify published field identity rules

State explicitly that a published field keeps its ID, name, and type while a replacement is added as a separate field under an unused ID.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9825b012-e653-496a-9310-c1f4b6f8ac27
This commit is contained in:
Jesper Schulz-Wedde 2026-07-15 09:29:18 +02:00
parent 958b033535
commit 26f7cb72a8
2 changed files with 6 additions and 6 deletions

View file

@ -3,10 +3,10 @@ table 50310 "Customer Profile Good"
fields
{
field(1; "No."; Code[20]) { }
// Replacement field receives a new ID in this independent example.
// Replacement is a separate field under an otherwise unused ID.
field(2; "Contact Email"; Text[80]) { }
// Old field keeps its original ID and is marked Pending so dependent code
// keeps compiling while an upgrade codeunit migrates its data.
// Old field keeps its original ID, name, and type and is marked Pending so
// dependent code keeps compiling while an upgrade codeunit migrates its data.
field(3; "Email"; Text[80])
{
ObsoleteState = Pending;

View file

@ -7,7 +7,7 @@ countries: [w1]
application-area: [all]
---
# Obsolete published table fields instead of deleting or renumbering them
# Obsolete published table fields instead of deleting, renaming, or renumbering them
## Description
@ -15,12 +15,12 @@ A shipped table field carries both a source-level contract and persisted data. R
## Best Practice
Add the replacement field under a new ID, then mark the old field `ObsoleteState = Pending` with an `ObsoleteReason` that names the replacement and an `ObsoleteTag` recording the obsoletion version. Keep the old field readable so an upgrade codeunit can copy its data during the deprecation window. Move it to `ObsoleteState = Removed` only in a later release, after the window has passed and data has migrated.
Keep the old field's ID, name, and type unchanged. Add the replacement as a separate field under an unused ID, then mark the old field `ObsoleteState = Pending` with an `ObsoleteReason` that names the replacement and an `ObsoleteTag` recording the obsoletion version. Keep the old field readable so an upgrade codeunit can copy its data during the deprecation window. Move it to `ObsoleteState = Removed` only in a later release, after the window has passed and data has migrated.
See sample: `obsolete-table-fields-instead-of-deleting-them.good.al`.
## Anti Pattern
Renaming published `Email` to `Contact Email` with the same ID violates the compatibility contract and AS0005, even though the retained ID does not itself imply a fresh empty column. Deleting `Email` or moving the replacement to another ID without migration additionally risks losing its stored values. Detection: a previously shipped field removed, renumbered, or renamed with no retained `Pending` field and migration path.
Renaming published `Email` to `Contact Email` with the same ID violates the compatibility contract and AS0005, even though the retained ID does not itself imply a fresh empty column. Deleting `Email` or changing its ID additionally risks losing its stored values. Detection: any previously shipped field whose name changes at the same ID, or whose original ID disappears without the unchanged field being retained as `Pending` and its data migrated to a separate replacement field.
See sample: `obsolete-table-fields-instead-of-deleting-them.bad.al`.