Annotation Interface Parent


@Documented @Target({FIELD,METHOD}) @Retention(RUNTIME) public @interface Parent
On a Model, registers a directed Graph relationship whose property contains one parent ID or a collection of parent IDs.

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. The Model-only maxChildren(), required() and preventParentDeletion() shorthands do not apply to schedule or command payload declarations. 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.

A Collection (including List and Set) registers one edge per distinct parent ID, using the same path and policies for each edge. A null or empty collection has no parents; null elements, raw collections, nested collections, arrays and maps are not supported. The collection element type supplies the ID type. Collection order does not define Graph child ordering. Field and getter declarations behave identically. Deleting any owning parent still deletes the child; use deleteOnParentDeletion = false for shared, independently retained children. Parent-scoped identity still requires one unambiguous parent scope.

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 persistence and search activation. This path alone creates no document. Enable Model.searchable() on the child or on an ancestor whose searchable scope includes this composed edge. Indexed canonical nodes then support both direct and relationship queries, including search(Child.class).whereParent(parentId), without requiring DOCUMENT persistence. An ancestor-ID filter needs no searchable parent; a parent-content predicate requires an indexed parent node. Identity-based Graph navigation needs neither search documents nor an 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 alone does not block deletion of the referenced parent; use preventParentDeletion() for the equivalent SDK-provided domain check. 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 load a parent on child reads. Mutations load parents only when otherwise needed, including applicable cascading assertions. 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.
    int
    On a Model relationship, maximum distinct children of this logical Model type and composition path for one parent.
    Optional slash-separated, non-reserved collection path relative to the parent document.
    boolean
    On a Model relationship, rejects logical deletion of a referenced parent while this relationship survives the final mutation state.
    boolean
    Whether searchability may propagate from the referenced parent through this relationship.
    boolean
    On a Model relationship, requires at least one referenced parent and requires every referenced parent to exist in the final mutation state.
    Class<?>[]
    Explicit possible parent model types for a polymorphic Id property.
    boolean
    Whether cascading assertions on this parent and its ancestors apply to this child and its descendants.
    Explicit parent model type for an untyped ID.
  • Element Details

    • validateAncestors

      boolean validateAncestors
      Whether cascading assertions on this parent and its ancestors apply to this child and its descendants. False stops only this route; other parent routes and the child's own assertions remain active. This is local SDK policy, independent of deletion/search policies; annotation changes need no stored rewrite.
      Default:
      true
    • 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:
      ""
    • propagateSearch

      boolean propagateSearch
      Whether searchability may propagate from the referenced parent through this relationship.

      This setting does not make either Model searchable by itself. Model.searchable() starts a searchable scope; this setting controls whether that scope may propagate across this relationship.

      Search propagation only applies when this relationship participates in search composition through a non-empty pathInParent(). This setting does not create a composition path. A pathless parent relationship remains available for ordinary Graph navigation and relationship predicates, but does not inherit search activation.

      When true (the default), a searchable parent can make this child and its composed descendants effectively searchable even when the child's own Model.searchable() value is false. When false, the complete branch is excluded from ancestor search Graphs and Graph-document notifications, in every projection mode, and inherited searchability stops at this edge.

      The child may still activate its own searchable scope, or inherit searchability through another included parent relationship. Ordinary Graph navigation, response composition, persistence, loading by identity, deletion policy and schedule ownership remain independent.

      This policy is persisted with the relationship. Existing relationships retain their previous policy until explicitly rewritten; an annotation change or an ordinary value-only update does not rewrite them. Rebuild existing stored Graph projections after migrating the relationships.

      Default:
      true
    • 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
    • maxChildren

      int maxChildren
      On a Model relationship, maximum distinct children of this logical Model type and composition path for one parent. Pathless relationships of the same child Model type share a limit. Different child types or paths do not. -1 means unlimited; zero disallows increasing the child count. Values below -1 are invalid.

      This is an SDK shorthand for a Graph-based domain check. The consumed relationship collection participates in normal Model conflict detection, so concurrent additions or moves trigger the configured conflict/retry flow. Existing overcapacity may remain while the final count does not grow.

      Default:
      -1
    • required

      boolean required
      On a Model relationship, requires at least one referenced parent and requires every referenced parent to exist in the final mutation state. A parent and child may be created together. For collection-valued parent properties, an empty collection is treated like an absent reference.

      This is an SDK shorthand for reading and checking the referenced Models in the same mutation. Those reads use the existing Model conflict contract; no separate Runtime constraint is installed.

      Default:
      false
    • preventParentDeletion

      boolean preventParentDeletion
      On a Model relationship, rejects logical deletion of a referenced parent while this relationship survives the final mutation state. This takes precedence over deleteOnParentDeletion(): the SDK does not cascade this edge. Explicitly deleting the child in the same mutation permits parent deletion; detaching does too when the final reference still satisfies required(). Administrative hard erasure is outside this domain check.
      Default:
      false