The Anatomy of a Business Object

reviewed: 23 February 2025

We have already learned that each .cms file in the bo folder is, by definition, a business object. It was also mentioned that business objects are sometimes referred to as entities. Probably time to explain the subtle difference between these terms.

A .cms file in the bo folder contains the definition of a business object. It is however not a business object (often abbreviated to BO). The correct term for the definition is entity. A BO is an instantiation of an entity.

The file client.cms is an entity defining what a client object looks like. I can create an instance of this entity and load the data in memory for 'NewCo Ltd from Mansfield' and that would be a business object.

Each entity consists of the following components:

Component Usage
Any diretives Such as inherits, cache or trace
The main function The function called when an instance of this entity is created
The @bo resource The definition of the entity
The _eventAction function Function invoked at specific system events
Conditions Conditions of this entity
Methods Methods of this entity
Resources Resources (other than <@bo> ) of this entity

Some Behind the Scenes Details

It is good to have some understanding of what happens 'under the hood' when you deal with business objects.

We have seen the bo.create function to create an instance of a BO:

    set( 'bo', bo.create( 'client' ) )
  1. CaseMaster will check whether the BO script client.cms is already in cache; if not it will try and load the file, parse the contents and store it in cache
  2. The main function of the BO script will be called (invoked) and this will return a <@bo> property bag
  3. The property bag will be used to create a so called descriptor Object
  4. A BO object is created (this is not yet of a specific type)
  5. The descriptor BO is linked to the BO object; now the BO is of type client

The @bo Resource

The <@bo> property bag is a so-called qualified property bag. This concept is explained in more details here.

The <@bo> property bag describes in great detail how a BO of this entity type should behave. Hence the term descriptor.

Tag Usage Example Optional / Mandatory
label The label of the entity 'Client' Optional
table The table in the database where the data is stored 'cdClient' Optional
inLineView Query that can be used instead of a table name 'select * from cdClient' Optional
dataSource The datasource the BO is connected to 'primary' Optional
size Indication of number of rows in the table / view entitySize.Small Optional
primaryKey Name of the attribute that is the primary key 'id' Optional
uniqueConstraint Optional attribute group that must have unique value 'client,name' Optional
useOwnDataSourceForSequence Indicates that datasource has its own sequence table false() Optional
sequence Name of sequence in sequence table 'cdClient' Mandatory in case one of attributes is of type automatic
sequenceStep Step to increase sequence by 2 Optional
deleteRule Indicates whether / how delete is allowed deleteRule.NotAllowed Optional
memoryPinMode Is BO memory pinned memoryPinMode.None Optional
auditable BO auditing settings auditing.None Optional

The following tags all are property bags themselves and will be explained later in this document:

Tag Usage Optional / Mandatory
deleteRelations Details on delete rules Mandatory when deleteRule has been set to deleteRule.PerRelation
tags Tags that can be linked to a descriptor Optional
enhancers Rules to enhance behavior of descriptor Optional
attributes The attributes of the descriptor Mandatory
attributeGroups Named attribute groups Optional
audits Audit types Optional
indexes Indexes Optional
Security Security rules Optional

Attributes

Attributes are described in more detail here.

Attribute Groups

Attribute groups are described in more detail here.

Audit Types

Audit types are described in more detail here.

Security

The security section can be used to define who can select, delete, insert or update BO's for this entity. It should be seen as a last defence. Typically you will build access control into your application (e.g. when you are not allowed to delete a client, there should be no delete button). CaseMaster will check the security rules at the very lowest level and so they can act as a last defence in case access control has not been implemented correctly elsewhere in the application.

See also here to learn more about security.

    security: <@bo/security
        canDelete: $inGroup( 'DEVL' )
        canUpdate: true()
    >

Delete Rule and Delete Relations

Delete rules are described in more detail here.

Indexes

The indexes section is not used often but can be used to describe the indexes that need to be present on the associated table as an absolute minimum.

Indexes have no impact on the workings of a descriptor or BO but are used when generating DDL.

    indexes: <
        <@bo/index
            name: 'ixClient'
            group: 'name,status'
            include: 'dob'
            unique: false()
        >
    >

The _eventAction Function

Event actions are described in more details here.

Conditions

Conditions are described in more details here.

Methods

We have already seen method in actions in previous documents. Methods are simply functions in BO scripts. Do not that the static access modifier is available for methods but not for functions of all other script types.

A static method is a function that can be called on the definition of an entity, not an instance of an entity.


    set( 'c', bo.quickLoad( 'client', 10 ) )        // Load BO with PK 10

    bo.invoke( [c], 'someMethod' )
    bo.invoke( 'client, 'someStaticMethod' )

Tags

Tags have two purposes; you can add custom tags to a descriptor for use somewhere in your system. This can be useful when are writing generic code that supports business objects of various entities. You may want to use a specific tag to drive certain behaviour.

The following example shows a snippet of code where a specific tag is checked.

    if boDesc.getTag( [BO], 'sensitive' )
        // Do something special
    else
        // Do something else
    end-if 

Each tag is a property bag tag:

    tags: <
        sensitive: false()
    >

There is a number of reserved tag names that have a specific meaning for CaseMaster. These are:

Tag Usage Example
forceSQLUpdate Always update database using SQL (and not a data adapter ) true()
forceSQLInsert Always insert into database using SQL (and not a data adapter ) true()
qsearchEntitySize Force the entity size for qsearch purposes 0
readNoLock Force readNoLock on all select statements true()

Read here about quick search and entity size.

<End of document>