Annotation Interface Parent


@Documented @Target({FIELD,METHOD}) @Retention(RUNTIME) public @interface Parent
On a Model, registers a directed Graph relationship whose property contains the referenced parent Model's ID.

Choose which relationships belong in the Graph first, then choose each relationship's deletion policy. A plain typed Id without this annotation stores a reference but registers no Graph edge. This annotation defaults to cascade deletion; @Parent(deleteOnParentDeletion = false) expresses a normal non-owning Graph relation. For example, a LineItem can have an owning @Parent OrderId orderId and a non-owning @Parent(deleteOnParentDeletion = false) ProductId productId: deleting the order deletes the line, whereas deleting the product does not.

On a scheduled message or command payload, this also declares schedule ownership: deletion of any referenced, already committed Model asynchronously cancels the schedule. Applicable @Apply returns of null, cascaded deletion and hard erasure all invalidate ownership. Null references and deleteOnParentDeletion = false do not own the schedule. The schedule is not a Model or Graph node; pathInParent and apiDoc do not compose it. Already delivered work cannot be recalled. Explicit Schedule.withParents(Object...) selections override these declarations.

Both sides remain independent model and persistence boundaries. Use a parent relationship when the child has its own creation, update history, retention, or deletion lifecycle but belongs in the parent's domain graph. Being rendered below the parent, or being deleted with it by default, does not turn the child into an embedded Member. A child identifier that is meaningful only below this parent can use EntityId.parentScoped().

A parent reference is stored independently from both model values so changing this property can attach, detach, or move the child without loading or rewriting either parent. A null value means that the property currently has no parent. Non-null values use their Object.toString() representation as the referenced model identity.

The parent model type is inferred when the property is an Id<T>. For a String or another untyped ID, value() may name the parent model explicitly. An explicit type is required only for features that need parent model metadata, including automatic graph-document composition. A typed parent may target the declaring model type itself, for example to represent folders within folders. Concrete relationship cycles are rejected atomically when the relationship change is committed.

pathInParent() is an optional path relative to the parent document. Supplying it opts this edge into automatic virtual-document stitching and CQRS graph placement. Omitting it leaves relationship navigation and graph bundles available without silently deriving a durable document path from a Java class name. The path names a list-valued collection: the runtime appends deterministic numeric child positions, so numeric path segments are not allowed. Graph placement is independent from Model.persistence(): a child without a direct document but with an explicit path is retained in a type-isolated private current-document collection for composition and indexed relationship selection, but is not exposed through its own collection. Parent and Graph searches can therefore select matching children first and traverse their current relationship edges without composing unrelated roots. This enables scoped search(Child.class).whereParent(parentId) without DOCUMENT on the child. The parent does not acquire a document simply by being referenced: a related parent-content predicate or searchGraph(Parent.class) still needs the parent's own current document. Identity-based Graph navigation needs neither document nor explicit composition path. apiDoc() optionally describes the list-valued property created at that path when the graph is used as a documented web response. It has no effect unless pathInParent() is set.

By default the relationship also owns the child's lifecycle: deleting the referenced parent deletes this model and its likewise owned descendants in the same atomic model commit. Set deleteOnParentDeletion() to false for a non-owning relation, including shared or independently retained children. Disabling cascade does not block deletion of the referenced parent; enforce such restrictions with domain rules. It also does not permit concrete Graph cycles. This lifecycle rule does not require a graph path and moving a child by changing its parent ID does not count as parent deletion. Sole-Graph event/notification handlers for a cascaded child observe its empty current value and historical before-state through the original published event, just as for a direct logical deletion. Reading that before-state requires stored history; DOCUMENT-only persistence does not retain previous document versions.

Declaring metadata does not cause a parent to be loaded when the child is loaded or updated. A one-to-one companion model may annotate the same property with EntityId; entity-ID affixes affect only the companion's repository identity and do not alter the parent reference value.

See Also:
  • Optional Element Summary

    Optional Elements
    Modifier and Type
    Optional Element
    Description
    Optional API documentation for the list-valued graph property at pathInParent().
    boolean
    Whether this model is deleted when the referenced parent is logically deleted.
    Optional slash-separated, non-reserved collection path relative to the parent document.
    Class<?>[]
    Explicit possible parent model types for a polymorphic Id property.
    Explicit parent model type for an untyped ID.
  • Element Details

    • value

      Class<?> value
      Explicit parent model type for an untyped ID. Must match the inferred Id target when both are present.
      Default:
      void.class
    • types

      Class<?>[] types
      Explicit possible parent model types for a polymorphic Id property.

      At runtime the concrete Id subtype selects exactly one of these model types through its declared type. This keeps graph validation, API documentation, cascade deletion and cycle detection statically knowable while allowing one domain property such as Id<?> nominee to refer to different model types. This attribute and value() are mutually exclusive. The standard serializer preserves polymorphic IDs as an object with name (logical Model name) and id (functional ID). Each allowed Model must declare its concrete ID class as EntityId. This allowlist is also enforced when reading the discriminator; unknown or ambiguous names are rejected.

      Default:
      {}
    • pathInParent

      String pathInParent
      Optional slash-separated, non-reserved collection path relative to the parent document.
      Default:
      ""
    • apiDoc

      ApiDoc apiDoc
      Optional API documentation for the list-valued graph property at pathInParent().

      The child item schema is inferred from the model that declares this parent reference. Nested path segments are represented as objects, while the final path segment is represented as an array of child models. Structural ApiDoc hints such as ApiDoc.type(), ApiDoc.format(), and ApiDoc.implementation() cannot override that inferred array and child type. Use ApiDoc.exclude() to keep this relationship out of every documented graph while retaining it in the runtime model graph.

      Default:
      @io.fluxzero.sdk.web.ApiDoc
    • deleteOnParentDeletion

      boolean deleteOnParentDeletion
      Whether this model is deleted when the referenced parent is logically deleted.

      The default expresses parent-owned child lifecycle. Set this to false for a non-owning Graph relation or a model which must remain independently addressable after this parent disappears. The policy is per edge: another owning parent may still cascade deletion to the same child. This setting does not prevent parent deletion or relax Graph cycle checks.

      Default:
      true