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
Fix: calculated-field evaluation must not persist via a spurious Update (#340)
* Fix: calculated-field evaluation must not persist via a spurious Update
When XrmMockup evaluated a classic calculated field during a
Retrieve/RetrieveMultiple, the parsed calc workflow reached its terminal
SetAttributeValue node and issued a real orgService.Update of the record.
That write was wrong regardless: a calculated field should only compute a
value and project it onto the returned entity. The spurious Update fired the
update pipeline, bumped modifiedon, and ran UpdateRequestHandler's
HasCircularReference guard — which rejects any record legitimately carrying a
self-referential lookup (e.g. a systemuser whose createdby is itself),
surfacing as the "circular reference" FaultException in the bug report.
Fix (smallest change satisfying the constraints): add a suppressWrites
parameter to WorkflowTree.Execute. It sets a "SuppressWrites" sentinel into
Variables *after* Reset() (which reinitializes Variables), and
SetAttributeValue.Execute returns instead of calling orgService.Update when
the sentinel is set. ExecuteCalculatedFields passes suppressWrites: true; the
computed value is already left in the primaryEntity variable and copied back
as before. All other callers (real workflows via WorkflowManager, rollups via
CalculateRollupFieldRequestHandler) keep the default false and still persist.
ExecuteFormulaFields uses the PowerFx evaluator and never reaches
SetAttributeValue, so it needs no change.
Removing the write exposed a pre-existing latent NRE in
Utility.GetFormattedValueLabel: a Money attribute's formatted value
dereferenced transactioncurrencyid without a null check. Previously the
spurious Update ran HandleCurrencies and backfilled the currency; without the
write, a calculated Money column can be projected onto a record that has no
currency, and RetrieveMultiple's SetFormattedValues threw. Guard the Money
branch to omit the formatted value when there is no currency, mirroring the
tolerant Lookup branch beside it.
Regression test (TestMoney.TestCalculatedFieldRetrieveDoesNotPersistAsUpdate):
creates a ctx_parent, advances the mock clock, then reads the calculated Money
column via both Retrieve and RetrieveMultiple. Before the fix modifiedon
jumped forward by the clock advance (proving a spurious Update); after, it is
unchanged and the calc value is still projected. Full net8.0 suite: 620
passed, 1 skipped, 0 failed (green across repeated runs).
Co-authored-by: Claude <noreply@anthropic.com> via Conducktor <conducktor@contextand.com>
Copy file name to clipboardExpand all lines: RELEASE_NOTES.md
+4Lines changed: 4 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,3 +1,7 @@
1
+
### 1.18.5 - 1 July 2026
2
+
* Fix: Evaluating a classic calculated field during Retrieve/RetrieveMultiple no longer issues a spurious `Update` of the record. The calculated value is now computed and projected onto the returned entity without persisting, so reads no longer bump `modifiedon`, fire update plugins, or trip the update-time circular-reference guard (which rejected records carrying a self-referential lookup, e.g. a `systemuser` whose `createdby` is itself). Real workflows and rollup fields still update as before.
3
+
* Fix: RetrieveMultiple no longer throws when building the formatted value for a Money attribute that has no associated `transactioncurrencyid` (e.g. a calculated Money column projected onto a record without a currency); the formatted value is simply omitted.
4
+
1
5
### 1.18.4 - 1 July 2026
2
6
* Fix: AppendTo/security checks for business- and organization-owned entities (#339)
0 commit comments