Property Calculator Breaking Changes and Upgrade Guide

Overview

This page compares the legacy M-Files Property Calculator, which evaluated expressions with the DataTable.Compute() engine, against the current NCalc-based Property Calculator (26.7.x), showing administrators what may break before upgrading and which issues the dashboard’s Upgrade from Legacy PC button fixes automatically versus which require a manual edit.

Baseline for this comparison: the legacy M-Files Property Calculator, which evaluates numeric value expressions and conditions with the legacy DataTable.Compute() engine. The current version replaced that engine with NCalc 6.1.1 on 2026-03-12, and that single change is the source of almost every breaking difference below.

How to Read This Document

Each change is tagged with how it is resolved:

Tag Meaning
🟢 Auto (button) Fixed automatically by the 🔄 Upgrade from Legacy PC dashboard button.
⚙️ Auto (runtime) Handled automatically while the expression is evaluated — no action needed.
🔴 Manual You must edit the configuration yourself; no automatic conversion exists.

Important scope note: the Upgrade button converts conditions (basic/advanced conditions, “Comparing to Main Object”, related-object filters, and automatic-update filtering conditions) and the value expression of a Calculate Expression property whose target is numeric or boolean — i.e. exactly the values the legacy engine evaluated through DataTable. Text, date and lookup value expressions were only expanded from placeholders (never DataTable), so they carry no legacy operator syntax and are intentionally left untouched.

At a Glance

# Old behavior (Legacy PC) New behavior (Current 26.7.x) Breaks? Resolution
1 AND / OR / NOT (any case) Lowercase and / or / not only ✅ Yes 🟢 Auto (button)
2 Field LIKE '*abc*' (operator, */?) LIKE(Field, '%abc%') (function, %/_) ✅ Yes 🟢 + ⚙️ Auto
3 ISNULL, LEN, CONVERT, IN(...), etc. NCalc equivalents (ifnull, length, tonumber, or/contains) ✅ Yes 🔴 Manual
4 “Comparing to Main Object” condition type Advanced Condition using mainObject(...) ⚠️ Compat only 🟢 Auto (button)
5 “Update Immediately” (Yes/No) “Update delay (minutes)” ⚠️ Config model 🟢 Auto (button)
6 Automatic update rules had no key Rules require a stable Rule Key ⚠️ Config model 🟢 Auto (button)
7 MFiles.PropertyCalculator.ObjectUpdateQueue NVS namespace Backlog lives in the VAF task queue + overflow/dead-letter ⚠️ Integrations 🔴 Re-point external tools

✅ Yes = an unchanged configuration can produce a wrong result or an error. ⚠️ = the configuration still runs, but the underlying model or storage changed.

The One Big Change: DataTable → NCalc

The legacy Property Calculator builds numeric value expressions and advanced conditions as System.Data.DataTable compute strings. (Text fields were only expanded to literal text, and date/boolean fields used their own resolvers — DataTable was never involved there.) The current version removed that engine entirely (it was also an injection risk) and now evaluates everything with NCalc 6.1.1, using parameterized, injection-safe evaluation where untrusted property values are bound as typed parameters instead of being concatenated into the expression text.

The two engines share a lot of surface syntax (+ - * /, < <= > >=, =, string literals in single quotes), which is why most configurations keep working. The differences that do break are listed below.

See also: NCalc Expressions for the complete NCalc reference and the full list of 50+ functions available in the new engine.

Breaking Changes in Detail

1. Uppercase AND / OR / NOT

Old: DataTable accepts logical keywords in any case — AND, And, and all work.

New: NCalc requires lowercase and, or, not. Uppercase keywords fail to parse.

❌  %PROPERTY_{PD.A}% > 0 AND %PROPERTY_{PD.B}% > 0
✅  %PROPERTY_{PD.A}% > 0 and %PROPERTY_{PD.B}% > 0

Symptom: an expression error, or a condition that silently never evaluates true.

Resolution:

2. LIKE operator and * / ? wildcards

Old: DataTable uses LIKE as an operator with * / ? (or % / _) wildcards: FullName LIKE '*son'.

New: NCalc has no LIKE operator — LIKE is a function, and wildcards are SQL-style (% = any run of characters, _ = a single character):

❌  %PROPERTY_{PD.Name}% LIKE '*son'
✅  LIKE(%PROPERTY_{PD.Name}%, '%son')

Resolution:

3. DataTable-only functions and syntax

The legacy PC evaluated a placeholder-expanded, literal expression on an empty, column-less DataTable — and only for a numeric value or a boolean/advanced condition. That distinction matters:

Legacy PC (DataTable, on literals) NCalc replacement Notes
IN (a, b, c) x == a or x == b or x == c NCalc has no SQL IN list operator.
ISNULL(a, b) ifnull(a, b) or coalesce(a, b) Returns a unless null/empty, else b.
CONVERT(x, 'System.Int32') tonumber(x) / tostring(x) Type-specific conversion functions.
LEN(x) length(x)  
SUBSTRING(x, 1, 3) substring(x, 0, 3) Index base differs: DataTable is 1-based, NCalc substring is 0-based.
IIF(c, t, f) iif(c, t, f) ✅ Still works — function names are case-insensitive.

Symptom: an Unknown function / parse error, or an off-by-one result after a SUBSTRING migration.

Resolution:

Decimal separator: the legacy PC silently converted commas to dots for numeric fields, so a literal 2,5 worked. NCalc uses . for decimals and , as the argument separator, so a literal 2,5 in an expression fails to evaluate — write 2.5. (Comma decimals inside placeholder values are still normalized automatically; this only affects literal numbers typed into an expression.)

4. “Comparing to Main Object” condition type

Old: A dedicated condition type “Comparing to Main Object” with From Main Object, Comparing Options and From Related Object fields.

New: The condition type still evaluates, but the modern form is an Advanced Condition that wraps the main-object part in the mainObject(...) function:

mainObject(%PROPERTY_{PD.Budget}%) >= %PROPERTY_{PD.Cost}%

Resolution:

5. “Update Immediately” replaced by “Update delay (minutes)”

Old: Related-object update rules had an Update Immediately (Yes/No) toggle.

New: That boolean is replaced by Update delay (minutes) — a numeric delay before the dependent object is updated in the background.

Resolution:

6. Automatic update rules now need a Rule Key

Old: Automatic object-update rules had no stable identifier.

New: Each automatic update rule carries a Rule Key used to track per-rule progress, scheduling and backlog state. Rules imported from the legacy configuration have no key.

Resolution:

7. The NVS update queue was removed

Old: The related-object update backlog was tracked in a single Named Value Storage namespace, MFiles.PropertyCalculator.ObjectUpdateQueue. (There was no separate “stuck” queue in the legacy / year-turn version — that came and went later in the current version’s line.)

New: That namespace no longer exists. The backlog now lives in the VAF task queue, with an overflow buffer and a dead-letter namespace for failures. See NVS Namespaces and Background Operations.

Resolution:

What Still Works Unchanged

These commonly-used constructs behave the same in both engines, so they need no attention:

Upgrade Button Coverage Matrix

What the 🔄 Upgrade from Legacy PC button (dashboardUpgrade from Legacy PC) does, and does not, do:

Task Covered by button?
Lowercase AND / OR / NOT in conditions ✅ Yes
<>!= in conditions ✅ Yes
LIKE operator → LIKE() function in conditions ✅ Yes
“Comparing to Main Object” → mainObject(...) Advanced Condition ✅ Yes
Migrate Update ImmediatelyUpdate delay (minutes) ✅ Yes
Generate missing Rule Keys for automatic update rules ✅ Yes
Migrate the legacy %X.FOREACH%+%Y% sum idiom → Sum(%X.Y%) ✅ Yes
* / ?% / _ in LIKE patterns ⚙️ Runtime (not the button)
Operator conversions inside numeric/boolean value expressions ✅ Yes
Operator conversions inside text / date / lookup value expressions N/A — placeholder-only, no operators
Translate DataTable-only functions (ISNULL, LEN, CONVERT, IN, …) ❌ No — manual
Re-point integrations that read the old NVS queue namespaces ❌ No — manual

The button is idempotent: running it again when everything is already converted reports “No conversion needed” and changes nothing. It also saves the configuration and records a configuration-history version, so the change is auditable and reversible.

  1. Back up the current configuration (export the JSON, or note the current configuration-history version so you can roll back).
  2. Install the PropertyCalculator .mfappx in the vault. At this point the application has no configuration yet — the dashboard buttons act on the saved configuration, so you must import your config before anything can be converted.
  3. Import your existing configuration JSON. In M-Files Admin, open the application’s Configuration editor, paste/import your JSON, and Save. This becomes the current configuration; legacy fields (e.g. Update Immediately, Comparing to Main Object) are preserved for the next step.
  4. Open the dashboard in M-Files Admin and click 🔄 Upgrade from Legacy PC. It reads the saved configuration, converts it in place, and saves it back.
    • The confirmation message reports how many expressions were converted, how many rules were migrated to update-delay, and whether rule keys were generated.
  5. Review the converted configuration for the manual (🔴) items above:
    • Value expressions that use DataTable-only functions (ISNULL, LEN, CONVERT, IN, …) — operator syntax (AND/OR/NOT, LIKE) in numeric/boolean value expressions is already converted.
  6. Use the Expression Builder (dashboardExpression Builder) to test any expression you edited before saving.
  7. Re-point any external tools/reports that read the old ObjectUpdateQueue namespace.
  8. Validate in a test vault before rolling out to production.

Post-Upgrade Validation Checklist

See also: Troubleshooting · NCalc Expressions · Dashboard · NVS Namespaces