How to Add Extended Fields to Entities Without Modifying Tables

Published: (December 19, 2025 at 06:57 AM EST)
4 min read
Source: Dev.to

Source: Dev.to

Video Demo

Based on the NopOrm engine built into the Nop platform, it’s very convenient to add extended properties to any entity.
These properties support querying and sorting, and are completely consistent with the entity’s built‑in properties in terms of usage.

How to enable extended fields

  1. Add the use‑ext‑field tag to the data table in the Excel data model.
  2. The system will enable global extended‑field support and store the values in the nop_sys_ext_field table.

nop_sys_ext_field table structure

Column NameType
entity_nameVARCHAR
entity_idVARCHAR
field_nameVARCHAR
field_typeINTEGER
decimal_valueDECIMAL
date_valueDATE
timestamp_valueTIMESTAMP
string_valueVARCHAR

The column that actually stores the value depends on field_type (e.g., decimal_value, date_value, …).

Generated ORM mapping

During compilation the “ tag reads the use‑ext‑field configuration and automatically generates the following mapping:

<!-- ORM mapping generated by the compiler -->

If keyProp is set in a one‑to‑many relationship, it marks that property as the unique identifier of the collection. The IOrmEntitySet collection then provides extension methods prop_get / prop_set that can directly access items by this key.

Accessing extended fields in Java

// read
IOrmKeyValueTable field = (IOrmKeyValueTable) entity.getExtFields()
                                                   .prop_get("fldA");

// write
entity.getExtFields().prop_set("fldA", value);

Accessing extended fields in XScript / EQL

extFields.fldA.string   // equivalent to entity.getExtFields().prop_get("fldA").getString()

fldA is resolved by locating the unique record in the one‑to‑many collection according to keyProp.


Using Aliases for Simpler Access

You can define aliases so that extended fields look like ordinary properties.

<!-- Alias configuration XML -->

After adding the alias configuration:

  • extFldA and extFldB become normal properties of the entity.
  • In Java you can use entity.prop_get("extFldA") or, if code is generated, the convenient methods:
entity.getExtFldA();          // getter
entity.setExtFldA(value);    // setter

When getters/setters are generated, you cannot use entity.prop_get for that field any more, because prop_get is reserved for properties that do not exist on the entity.

For a unified way to retrieve both built‑in and extended fields you can call:

entity.orm_propValueByName(name);

or use reflection utilities such as BeanTool.getProperty(entity, propName).

EQL queries with extended fields

Extended fields can be used in filtering, sorting, and projection exactly like built‑in fields:

select o.extFldA
from MyEntity o
where o.extFldA = '123'
order by o.extFldA

GraphQL Exposure

Add the property definition to the xmeta file so that GraphQL can query the extended fields:

<!-- xmeta configuration for GraphQL -->

Local‑Ext Tables (Performance Optimisation)

All extended fields are stored in nop_sys_ext_field by default, which can cause a large table and degrade performance.
To mitigate this, add the local‑ext tag to the entity table. The system will then generate a paired extended‑field table for that entity, typically named:

original_table_name + '_ext'

Example: nop_sys_notice_template_ext

The local‑ext table has the same structure as nop_sys_ext_field except it does not contain the entityName column (filtering by entity name is unnecessary).

Note: Many low‑code platforms use a single vertical table to store all data, requiring a hard‑coded vertical‑to‑horizontal transformation. Nop’s approach with optional local‑ext tables avoids that complexity.


Example: Unit Test TestExtFields

<!-- Unit test configuration XML -->

Any to‑many relationship can be configured with a keyProp attribute to uniquely identify a record inside the collection.

The alias ext.fldA.string is equivalent to:

((IOrmEntitySet) entity.getExt()).prop_get("fldA").getString();

Summary

  • Extended fields are added via use‑ext‑field and stored in nop_sys_ext_field.
  • The ORM generator creates a to‑many relation (extFields) with a keyProp.
  • Access is possible through prop_get/prop_set, generated getters/setters, or the unified orm_propValueByName.
  • Aliases turn extended fields into regular‑looking properties, usable in Java, XScript, EQL, and GraphQL.
  • For large‑scale usage, add local‑ext to create a dedicated table per entity, improving performance.

Extended Field Access and Code Generation

Naming Shortcut

In the configuration above, extFldA is equivalent to ext.fldA.string.
This gives a simple name to the complex path required for accessing extended fields.

Code Generation Flag

If notGenCode is marked, the getter/setter methods in Java will not be generated for this property during code generation.
Values must be obtained via methods such as:

entity.prop_get("extFldB");

Uniform Access Syntax

In XScript or XPL template languages, the access syntax for extended properties and ordinary properties is identical. You can directly assign values:

entity.extFldB = true;

EQL Automatic Recognition

In the EQL query language, keyProp is automatically recognized for structural transformation.


EQL Transformations

Simple Property Access

select o.children.myKey.value
from MyEntity o

Transforms to

select u.value
from MyEntity o
left join Children u
  on o.id = u.parent_id
 and u.key = 'myKey';

Flattening Collections

As long as a collection has a unique identifier, it can always be flattened into an associated property with a unique access path. The ORM engine’s EQL language handles the transformation of nested properties like o.a.b.c into the appropriate table‑join queries.

Multiple Key Filters

select o.name
from MyEntity o
where o.children.myKey1.intValue = 3
  and o.children.myKey2.strValue like 'a%';

Transforms to

select o.name
from MyEntity o
left join Children u1
  on o.sid = u1.parent_id
 and u1.key = 'myKey1'
left join Children u2
  on o.sid = u2.parent_id
 and u2.key = 'myKey2'
where u1.intValue = 3
  and u2.strValue like 'a%';

One‑to‑Many → One‑to‑One via Key Filter

select o.key1,
       o.children.myKey1.value,
       o.children.myKey2.value
from MyEntity o;

Transforms to

select o.key1,
       u1.value,
       u2.value
from MyEntity o
left join Children u1
  on o.sid = u1.parent_id
 and u1.key = 'myKey1'
left join Children u2
  on o.sid = u2.parent_id
 and u2.key = 'myKey2';

Deterministic Transformation Rule

According to the defined rules, extracting the related table from o.children.myKey is, at the mathematical level, a deterministic local transformation. The ORM engine applies this rule automatically, converting property‑path expressions into the corresponding SQL joins.

Back to Blog

Related posts

Read more »