# Rule: Child object relationships — ObjectLookup, NestedObject, ListObject

A BusinessObject can own three kinds of child relationships. Each is declared inside its own wrapper element and uses a consistent wiring pattern.

## The three relationship types

### `<ObjectLookup>` — 1:1 read-only reference to a LookupObject

Use when the parent BO needs data from a cached, read-only registry (LU). The LU is loaded using one property value from the parent as a lookup key.

```xml
<ObjectLookups>
  <ObjectLookup name="luOrderer"
                objectClass="LuOrderer"
                dataSourceProperty="ordererPKey"
                lookupProperty="pKey" />
</ObjectLookups>
```

-   `name` — camelCase reference used in BL: `me.getLuOrderer()`
-   `objectClass` — must match the LU's root `@name` attribute exactly
-   `dataSourceProperty` — the BO property whose VALUE is passed to the child
-   `lookupProperty` — the parameter NAME in the LU's DS that receives the value
-   Read-only: the LU participates in load but NOT in save
-   Default load: immediate (alongside parent load)

Real-file citation: `src/Order/BO/BoOrder/BoOrder.businessobject.xml` declares eight `<ObjectLookup>` entries including `luOrderer` and `luDeliveryRecipient`.

---

### `<NestedObject>` — 1:1 writable child BusinessObject

Use when the parent has a sub-entity that should be loaded and saved together with the parent. Common for role objects and detail sub-records.

```xml
<NestedObjects>
  <NestedObject name="boOrderMeta"
                objectClass="BoOrderMeta"
                dataSourceProperty="sdoMetaPKey"
                nestingProperty="pKey" />
</NestedObjects>
```

-   `name` — camelCase reference: `me.getBoOrderMeta()`
-   `objectClass` — must match the child BO's root `@name`
-   `dataSourceProperty` — the parent BO property whose VALUE is passed
-   `nestingProperty` — parameter NAME in the child BO's DS
-   Writable: child BO participates in the parent's save chain
-   `loadMode="onDemand"` defers loading until explicitly requested

Real-file citation: `src/Order/BO/BoOrder/BoOrder.businessobject.xml` nests `boOrderMeta` (objectClass `BoOrderMeta`), `boWorkflow`, and `boItemTabManager`.

---

### `<ListObject>` — 1:many writable collection (ListObject)

Use when the parent owns a collection of items that can be added, removed, or edited. The LO is loaded using the parent's pKey as a filter parameter.

```xml
<ListObjects>
  <ListObject name="loAssessmentTasks"
              objectClass="LoVisitAssessmentTask"
              dataSourceProperty="pKey"
              listProperty="visitId" />
</ListObjects>
```

-   `name` — camelCase reference: `me.getLoAssessmentTasks()`
-   `objectClass` — must match the LO's root `@name`
-   `dataSourceProperty` — parent property whose VALUE is passed (almost always `pKey`)
-   `listProperty` — parameter NAME in the child LO's DS (must match a DS `<Parameter name="...">`)
-   Writable: items can be created, modified, and deleted via the LO
-   Events available: `listItemChanged`, `listItemChangedBatch`

Real-file citations:

-   `src/Visit/BO/BoVisit/BoVisit.businessobject.xml` — line 32: `<ListObject name="loAssessmentTasks" objectClass="LoVisitAssessmentTask" dataSourceProperty="pKey" listProperty="visitId"/>`
-   `src/Order/BO/BoOrder/BoOrder.businessobject.xml` — multiple ListObjects including `LoItems` (objectClass `LoOrderItems`, listProperty `sdoMainPKey`)

---

## Wiring pattern (same logic for all three)

The parent-to-child key flow always follows this rule:

```
Parent BO property value → child DS parameter value
     dataSourceProperty  →  listProperty / nestingProperty / lookupProperty
```

Example trace for `BoVisit → loAssessmentTasks`:

```
BoVisit.pKey = "001O300001TYlYFIA1"          ← dataSourceProperty="pKey"
  ↓ passed as parameter
LoVisitAssessmentTask DS receives:
  jsonQuery = { visitId: "001O300001TYlYFIA1" }  ← listProperty="visitId"
  ↓ used in QueryCondition
  WHERE Task.VisitId = #visitId#
```

The `listProperty` (or `nestingProperty` / `lookupProperty`) value must exactly match a `<Parameter name="...">` in the child's DS.

---

## `loadMode` attribute

| Value                 | Behaviour                                                                    |
| --------------------- | ---------------------------------------------------------------------------- |
| _(absent or default)_ | Child loaded eagerly when parent loads                                       |
| `LoadImmediate`       | Same as default; explicit eager load                                         |
| `onDemand`            | Child NOT loaded automatically; call `me.loadChildAsync()` in BL when needed |

Use `loadMode="onDemand"` for expensive child collections that aren't always needed (e.g., a large product list in an order screen that's only visible on a specific tab).

---

## Wrapper elements must always be present

Even when empty, include the wrapper elements in the XML. The XML parsers in the modeler expect them:

```xml
<ObjectLookups/>
<NestedObjects/>
<ListObjects>
  <ListObject name="loTasks" objectClass="LoTasks" dataSourceProperty="pKey" listProperty="parentPKey"/>
</ListObjects>
```

Real-file citation: `src/Visit/BO/BoAccount/BoAccount.businessobject.xml` has all three wrappers present but empty.

---

## ListObject events

A `<ListObject>` entry can declare an event handler that fires when any item in the child collection changes:

```xml
<ListObject name="loItems"
            objectClass="LoOrderItems"
            dataSourceProperty="pKey"
            listProperty="sdoMainPKey">
  <Events>
    <Event name="listItemChanged" eventHandler="onOrderItemChanged" />
  </Events>
</ListObject>
```

Allowed event names: `listItemChanged`, `listItemChangedBatch`. The `eventHandler` must be declared in `<Methods>` and implemented in `.bl.js`.

---

## Choosing the right relationship

| Scenario                                                         | Use                              |
| ---------------------------------------------------------------- | -------------------------------- |
| Need display data from a registry (product name, user name)      | `ObjectLookup`                   |
| Need a writable sub-record (order metadata, workflow state)      | `NestedObject`                   |
| Need a list of items the parent owns (order lines, tasks, notes) | `ListObject`                     |
| Child is expensive and only needed on one tab                    | Any type + `loadMode="onDemand"` |
