Filed under: Best Practices, Core Updates
  Comments: 1

All Business Model Classes share a standard object lifecycle of new, create, read, update, delete, and more.  This article provides examples and details of how the read lifecycle event and its parameters work.

This information is available in other documents and help, but it is so important, I’ve put it here as well.  You can find the latest info in the dynamic help of NexJ Studio by hovering over the read statement in a script editor.  I’ll go into more detail in other posts.

read(attributes where orderBy count offset xlock): instance-collection

Reads specified instances of this class. The main action is implemented by the framework.


attributes list The list of attributes, or associated objects, to proactively retrieve. ‘() retrieves no attributes and any attributes accessed after such a read will trigger a lazy load. See examples for special downcast (@@) syntax and annotation syntax.
where list The where clause. See examples for information on associations, reverse associations and qualified associations.
orderBy list The expressions on which to order the collection – a list of (<sort-expr> . <ascending?>) pairs.
count integer The number of instances to retrieve. Null ‘() for the default value of -1, meaning up to the readLimit specified in the data source.
offset integer The number of top level instances to skip from the beginning of the retrieved collection. Null ‘() for the default value of 0.
xlock boolean If true, an exclusive lock is set in persistent storage on the matching top level objects until the transaction is finished. null ‘() for the default value of #f.


instance-collection Collection of instances matching the where clause.


Associated objects can be retrieved using nested lists in the attributes argument. Simply specify a non-primitive attribute name then a list of one or more attributes. e.g. (Entity’read ‘(firstName lastName (addrs city state zip)) These nestings can continue… e.g. (Entity’read ‘(firstName lastName (addrs city state zip (type name)))

Attributes can also be retrieved polymorphically – meaning attributes that only exist on subclasses can be retrieved when reading the base class. (see examples)
Attribute names in the where and order by clauses may take the simple form of <attributeName> or (@ <attributeName>). The second form is recommended. In this case the “@” represents the current instance and may be used to traverse arbitrarily long association paths. e.g. on User we may specify (= (@ person homeAddress city) “Toronto”)
One cannot pass in a larger count than readLimit defined in the data source. A count of -1 will not restrict the count, but if more than readLimit instances are returned, an error will be thrown. In cases where more than readLimit instances are desired, the openCursor method should be used. The helper function for-each-page can normally be used and provides a simplified API to openCursor.


=> ; #<[]> if Joe doesn’t exist
=> ; #<[Instance<Person, OID:1:V32:4AA92BA6E6A64CE5BBEB8… if Joe does exist

More advanced read

Use of the any operator – Reduces the multiplicity of an association to 1

1) Expressing queries that are impossible to do only with joins

In this example, return people who have at least one address in Toronto and at least one in Richmond Hill.  Nothing will be returned by the equals operator equivalent (Person’read … ‘(and (= (@ addrs city) “Toronto”) (= (@ addrs city) “Richmond Hill”)) …)

2) Optimizing database filtering on collection associations

In this example, database will return only one person record per macthing addresses vs returning as many copies of a person record as there are matching addresses when using the equals operator equivalent (Person’read … ‘(= (@ addrs city) “Toronto”) …)

Annotations in the attributes list – create calculated attributes on-the-fly

In this example, return the lastName attribute, a calculated _lnLen attribute which is the length of the last name, and a _fullName calculated attribute
We use the underscore here just to avoid name collisions.

Aggregate functions – can be applied to subcollections on instances

Supported operators include count, average, min, max, sum
For aggregation at the top level of the class, see the aggregate method

Attribute downcast syntax (@@) – Polymorphic read

Used to proactively load subclass specific attributes when reading from a base class

Conditions in where clause association paths

This syntax allows us to restrict parts of association paths to specific subclasses and also to apply arbitrary conditions on association paths

1) Most common use case: limit an association based on a qualifier e.g. look for all Entities with a user named “Shaw” playing their advisor role

2) Subclass restriction example: note that homeAddress is an attribute that is only found on the Person subclass of Entity

3) Arbitrary condition example: reads all instances of the Telcom class that has an entity with a lastname of “Shaw” that has an address in “Toronto” with and address2 line that is not null.

Note that conditions may be applied in reverse associations as well as forward associations

Where Clause reverse association syntax (@@)

Used to query from the end of an association “back” to the class you are reading.
Forward associations take the form (@ part1 part2 part3 …). The @ represents an instance of the class being read.
Reverse associations take the form (@@ <ClassName> part3 part2 part1) where part1 represents an attribute with a type of the class being read.
You can usually just navigate the forward association, but you may see this syntax if you are tracing requests from NexJ UI clients

About heterogeneous joins

Root class – Metaclass on which a read event is invoked.
Root datasource – Datasource to which a root class is persisted.
Heterogeneous join – A query contains a heterogeneous join when it references an attribute not stored in the root datasource.
Homogeneous association – An association is homogeneous if it can be retrieved without accessing another datasource. This is possible at present if its source key in the root datasource references a primary key in the another datasource (i.e. only the OID of the object is stored in the root data source).

The association used for filtering and/or sorting must be homogeneous.

For the examples, assume the following:
1. Root class – ConversationUser
2. Root datasource – Conversation
3. Other datasource – DefaultRelational
4. ‘from’ is an association on ConversationUser referencing a class in the other datasource

1) Filtering

2) Sorting

See Also

read-instance aggregate openCursor openAggregateCursor for-each-page


  Comments: 1

Your feedback

You must be logged in to post a comment.