From 7365326018424d9a7e0530b4a528c329d8c1b7d2 Mon Sep 17 00:00:00 2001 From: Vladimir Mikhaylenko Date: Fri, 6 Feb 2026 15:54:12 +0100 Subject: [PATCH 1/5] Add magic tricks section --- java/change-tracking.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/java/change-tracking.md b/java/change-tracking.md index 4a96b28f66..0602a61f07 100644 --- a/java/change-tracking.md +++ b/java/change-tracking.md @@ -436,6 +436,44 @@ public class ChangeTrackingHandler implements EventHandler { You can query the change log entries via CQN statements, as usual. +## Tips and Tricks + +### Entities from imported services + +In general, Change Tracking expects that everything that needs change tracking is stored in the local database. +You might, however, need to model an association to the remote entity that, as a general rule, requires custom implementation. +The only possible option with associations like this is to track changes for its foreign key values. + +:::warning Configuration change required! +Enable [optimization for path expressions](/releases/2025/aug25#optimized-path-expressions). +::: + +Let's take the following model as an example: + +```cds +@cds.external: true +entity Remote { + key ID : UUID; + ... +} + +entity Local { + key ID : UUID; + toRemote : Association to Remote; +} +``` + +You model the association like this: + +```cds +entity Local { + key ID : UUID; + toRemote : Association to Remote @changelog: [toRemote.ID]; // [!code focus] +} +``` + +The entity's primary key is the only field you can use here, as rest of the association's target fields is not readable with standard persistence. The change log will contain one entry for the field `toRemote` just like the other associations with [human-readable values](#human-readable-values-for-associations). + ## Things to Consider when Using Change Tracking - Consider the storage costs of the change log. The change log can grow very fast and can consume a lot of space From 8e1874f349835b24ab28666366d3cd9a5c71495b Mon Sep 17 00:00:00 2001 From: Vladimir Mikhaylenko Date: Mon, 9 Feb 2026 11:10:19 +0100 Subject: [PATCH 2/5] . --- java/change-tracking.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/java/change-tracking.md b/java/change-tracking.md index 0602a61f07..a1d08d19df 100644 --- a/java/change-tracking.md +++ b/java/change-tracking.md @@ -438,9 +438,9 @@ You can query the change log entries via CQN statements, as usual. ## Tips and Tricks -### Entities from imported services +### Entities from Remote Services -In general, Change Tracking expects that everything that needs change tracking is stored in the local database. +In general, Change Tracking expects that everything is stored in the local database. You might, however, need to model an association to the remote entity that, as a general rule, requires custom implementation. The only possible option with associations like this is to track changes for its foreign key values. @@ -474,6 +474,8 @@ entity Local { The entity's primary key is the only field you can use here, as rest of the association's target fields is not readable with standard persistence. The change log will contain one entry for the field `toRemote` just like the other associations with [human-readable values](#human-readable-values-for-associations). +If you need a custom identifier, it is up to you to implement in a custom handler. + ## Things to Consider when Using Change Tracking - Consider the storage costs of the change log. The change log can grow very fast and can consume a lot of space From 4b6eb05b565ad6fda3bb7d57e4020e6570d146af Mon Sep 17 00:00:00 2001 From: Vladimir Mikhaylenko Date: Mon, 9 Feb 2026 11:11:38 +0100 Subject: [PATCH 3/5] less words --- java/change-tracking.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/java/change-tracking.md b/java/change-tracking.md index a1d08d19df..b81f9c8a54 100644 --- a/java/change-tracking.md +++ b/java/change-tracking.md @@ -440,9 +440,8 @@ You can query the change log entries via CQN statements, as usual. ### Entities from Remote Services -In general, Change Tracking expects that everything is stored in the local database. -You might, however, need to model an association to the remote entity that, as a general rule, requires custom implementation. -The only possible option with associations like this is to track changes for its foreign key values. +Change Tracking expects that everything is stored in the local database. +If you need to model an association to the remote entity, the only possible option is to track changes for its foreign key. :::warning Configuration change required! Enable [optimization for path expressions](/releases/2025/aug25#optimized-path-expressions). From 8dc6b6cf69880357588b443072c030fbe365de62 Mon Sep 17 00:00:00 2001 From: Vladimir Mikhaylenko Date: Wed, 11 Feb 2026 10:00:51 +0100 Subject: [PATCH 4/5] Add example --- java/change-tracking.md | 54 ++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/java/change-tracking.md b/java/change-tracking.md index b81f9c8a54..4b7919cefc 100644 --- a/java/change-tracking.md +++ b/java/change-tracking.md @@ -438,10 +438,10 @@ You can query the change log entries via CQN statements, as usual. ## Tips and Tricks -### Entities from Remote Services +### Optimize Change Logs for Associated Entities -Change Tracking expects that everything is stored in the local database. -If you need to model an association to the remote entity, the only possible option is to track changes for its foreign key. +By default, the identifier is read from the association when the feature captures images of the data. +Additional joins might be expensive or impossible under some circumstances. :::warning Configuration change required! Enable [optimization for path expressions](/releases/2025/aug25#optimized-path-expressions). @@ -450,30 +450,56 @@ Enable [optimization for path expressions](/releases/2025/aug25#optimized-path-e Let's take the following model as an example: ```cds -@cds.external: true -entity Remote { - key ID : UUID; +entity User { + key ID : UUID; ... } -entity Local { - key ID : UUID; - toRemote : Association to Remote; +entity Entity { + key ID : UUID; + user : Association to User; } ``` +Let's assume that `User` is impossible to join with standard identifier or requires identifier depending on the context of the user who reads the change log. + You model the association like this: ```cds -entity Local { - key ID : UUID; - toRemote : Association to Remote @changelog: [toRemote.ID]; // [!code focus] +entity Entity { + key ID : UUID; + user : Association to User @changelog: [user.ID]; // [!code focus] } ``` -The entity's primary key is the only field you can use here, as rest of the association's target fields is not readable with standard persistence. The change log will contain one entry for the field `toRemote` just like the other associations with [human-readable values](#human-readable-values-for-associations). +The change log will contain one entry for the field `user` just like the other associations with [human-readable values](#human-readable-values-for-associations), but the identifier will be equivalent to the its primary key. + +You need a custom handler to fetch own custom identifier. + +Below is the sketch for the handler to adapt the change log after read: + +```java +@Component +@ServiceName(CatalogService_.CDS_NAME) +class ChangeLogHandler implements EventHandler { + + @After(event = CqnService.EVENT_READ) + //NB: Handler is executed before the standard conversion of changelog + @HandlerOrder(HandlerOrder.EARLY + HandlerOrder.EARLY) + void enhance(List result) { + result.stream().map(l -> l.getChange()).forEach(change -> { + if (change.getAttribute().equals(Entity.USER)) { + // Use either path or existing values to find out the primary key of the user + // and do your own conversion. + change.setValueChangedFrom("..."); + change.setValueChangedTo("..."); + } + }); + } +} +``` -If you need a custom identifier, it is up to you to implement in a custom handler. +Always consider performance implications with cases like this. The sequential read always needs proper batching and caching, otherwise you loose the performance advantage. ## Things to Consider when Using Change Tracking From 23eb378a5c9941811c9e271fecdb7bbf22ae337e Mon Sep 17 00:00:00 2001 From: Vladimir Mikhaylenko Date: Wed, 11 Feb 2026 10:04:23 +0100 Subject: [PATCH 5/5] Rename chapter --- java/change-tracking.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/change-tracking.md b/java/change-tracking.md index 4b7919cefc..3ccb274bb6 100644 --- a/java/change-tracking.md +++ b/java/change-tracking.md @@ -438,7 +438,7 @@ You can query the change log entries via CQN statements, as usual. ## Tips and Tricks -### Optimize Change Logs for Associated Entities +### Advanced Identifiers for Associated Entities By default, the identifier is read from the association when the feature captures images of the data. Additional joins might be expensive or impossible under some circumstances.