Member Junction
    Preparing search index...

    Extended MJEntityEntity class that provides automatic handling of Description field updates. When a user manually updates the Description, it automatically sets AutoUpdateDescription to 1 to prevent CodeGen from overwriting the custom description.

    Hierarchy (View Summary)

    Index

    Constructors

    Properties

    Accessors

    __mj_CreatedAt __mj_UpdatedAt ActiveUser AllowAllRowsAPI AllowCaching AllowCreateAPI AllowDeleteAPI AllowDirectSQLDelete AllowDirectSQLInsert AllowDirectSQLUpdate AllowMultipleSubtypes AllowRecordMerge AllowUpdateAPI AllowUserSearchAPI AuditRecordAccess AuditViewRuns AutoRowCountFrequency AutoUpdateAllowUserSearchAPI AutoUpdateDescription AutoUpdateFullTextSearch AutoUpdateSupportsGeoCoding BaseTable BaseTableCodeName BaseView BaseViewGenerated BoundProvider CanonicalSchemaName CascadeDeletes ClassName CodeName Companions Configuration ConfigurationObject ContextCurrentUser CustomResolverAPI DefaultSkipAsyncValidation DeleteType Description DetectExternalChanges Dirty DisplayName EnableFieldLevelSecurity EntityInfo EntityObjectSubclassImport EntityObjectSubclassName ExternalDataSourceID ExternalObjectName Fields FirstPrimaryKey FullTextCatalog FullTextCatalogGenerated FullTextIndex FullTextIndexGenerated FullTextSearchEnabled FullTextSearchFunction FullTextSearchFunctionGenerated GeneratedBaseViewName HasCompanions Icon ID IncludeInAPI ISAChild ISAChildren ISAParent ISAParentEntity IsBusy IsDeleting IsLoading IsSaved IsSaving LatestResult LeafEntity Name NameSuffix ParentBaseTable ParentBaseView ParentEntity ParentID PreferredCommunicationField PrimaryKey PrimaryKeys ProviderToUse RecordChanges RecordLoaded RelationshipDefaultDisplayType RestoreContext ResultHistory RootEntity RowCount RowCountRunAt RowsToPackSampleCount RowsToPackSampleMethod RowsToPackSampleOrder RowsToPackWithSchema RunQueryProviderToUse RunViewProviderToUse SchemaName ScopeDefault SkipEmbeddings spCreate spCreateGenerated spDelete spDeleteGenerated spMatch spUpdate spUpdateGenerated Status SubtypeSelector SubtypeSelectorObject SupportsGeoCoding TrackRecordChanges TransactionGroup TrustServerCacheCompletely UserFormGenerated UserViewMaxRows Vectors VirtualEntity BaseEventCode Provider

    Methods

    AfterEntityAIAction ApplyFieldLevelCreateSuppression AttachToParent BeforeEntityAIAction BindProvider BuildDeletePlan BuildSavePlan CascadeDeleteChildRecord CheckFieldLevelUpdatePermissions CheckForChildRecords CheckPermissions ClearRestoreContext Config ConstructUninitializedEntity CopyFrom DeclareEmbeddedRecord DeclareRelatedRecords Delete DeserializeCompanions EmbedTextLocal EnforceDisjointSubtype EnsureDeleteComplete EnsureISAChild EnsureLoadComplete EnsureSaveComplete FieldIsDirty From GenerateEmbedding GenerateEmbeddingByFieldName GenerateEmbeddings GenerateEmbeddingsByFieldName Get GetAll GetAncestors GetChangesSinceLastSave GetChildren GetCompanion GetDataObject GetDataObjectJSON GetDescendants GetFieldByCodeName GetFieldByName GetRecordName getRecursiveForeignKeyField GetRelatedEntityData GetRelatedEntityDataExt Hydrate InitializeChildEntity InitializeEmbeddedRecords InitializeParentEntity InnerLoad Load LoadFromData LoadRelatedRecords NewRecord RaiseEvent RaiseReadyForTransaction Refresh RegisterCompanion RegisterEventHandler RegisterResultHistoryEntry RegisterTransactionPreprocessing ResetVectors ResolveSubtypeEntityName Revert Save SerializeCompanions Set SetEmbeddedLoadVisited SetMany SetRestoreContext SupportsEmbedTextLocal ThrowPermissionError To Validate ValidateAllowRecordMergeForSoftDeleteAPI ValidateAsync ValidateDeleteTypeForDirectSQLDelete ValidateDirectSQLAndTrackingConstraints ValidateGeneratedBaseViewNameAndBaseViewGenerated ValidateGeneratedBaseViewNameDifferentFromBaseView ClearSubtypeLookupCache GetRecordChanges ResolveLeafEntity

    Constructors

    Properties

    MAX_RESULT_HISTORY: 50

    Maximum number of BaseEntityResult entries retained in _resultHistory per entity instance. Set to 50 — enough for diagnostic context while bounding worst-case memory for entities that survive thousands of Save/Delete cycles.

    Accessors

    • get __mj_CreatedAt(): Date
      • Field Name: __mj_CreatedAt
      • Display Name: Created At
      • SQL Data Type: datetimeoffset
      • Default Value: getutcdate()

      Returns Date

    • get __mj_UpdatedAt(): Date
      • Field Name: __mj_UpdatedAt
      • Display Name: Updated At
      • SQL Data Type: datetimeoffset
      • Default Value: getutcdate()

      Returns Date

    • get ActiveUser(): UserInfo

      Internal helper method for the class and sub-classes - used to easily get the Active User which is either the ContextCurrentUser, if defined, or the Metadata.Provider.CurrentUser if not.

      Returns UserInfo

    • get AllowAllRowsAPI(): boolean
      • Field Name: AllowAllRowsAPI
      • Display Name: Allow All Rows API
      • SQL Data Type: bit
      • Default Value: 0
      • Description: If set to 1, a GraphQL query will be enabled that allows access to all rows in the entity.

      Returns boolean

    • set AllowAllRowsAPI(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get AllowCaching(): boolean
      • Field Name: AllowCaching
      • Display Name: Allow Caching
      • SQL Data Type: bit
      • Default Value: 0
      • Description: Controls whether this entity participates in server-side and client-side caching. When false, all cache operations (PreRunView checks, auto-cache storage, BaseEntity event fingerprint scans, client-side IndexedDB cache) are skipped entirely. This column is the single source of truth at runtime; schema-level defaults are applied at CodeGen time via newEntityDefaults.AllowCachingBySchema.

      Returns boolean

    • set AllowCaching(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get AllowCreateAPI(): boolean
      • Field Name: AllowCreateAPI
      • Display Name: Allow Create API
      • SQL Data Type: bit
      • Default Value: 0
      • Description: Global flag controlling if creates are allowed for any user, or not. If set to 1, a GraqhQL mutation and stored procedure are created. Permissions are still required to perform the action but if this flag is set to 0, no user will be able to perform the action.

      Returns boolean

    • set AllowCreateAPI(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get AllowDeleteAPI(): boolean
      • Field Name: AllowDeleteAPI
      • Display Name: Allow Delete API
      • SQL Data Type: bit
      • Default Value: 0
      • Description: Global flag controlling if deletes are allowed for any user, or not. If set to 1, a GraqhQL mutation and stored procedure are created. Permissions are still required to perform the action but if this flag is set to 0, no user will be able to perform the action.

      Returns boolean

    • set AllowDeleteAPI(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get AllowDirectSQLDelete(): boolean
      • Field Name: AllowDirectSQLDelete
      • Display Name: Allow Direct SQL Delete
      • SQL Data Type: bit
      • Default Value: 0
      • Description: When 1, this entity may have rows removed by DELETE statements that do not go through BaseEntity.Delete() — purge and retention routines, or integration sync reconciling a remote source. Default 0, meaning every delete is expected to flow through BaseEntity so that record-change tracking, entity actions, cascade handling and cache invalidation all run. This column DECLARES intent for the code paths and tooling that consult it; it does not and cannot prevent anyone from executing SQL. Requires TrackRecordChanges = 0 and TrustServerCacheCompletely = 0, and additionally requires DeleteType = 'Hard' — a direct DELETE removes the row outright rather than setting DeletedAt, which would defeat soft delete.

      Returns boolean

    • set AllowDirectSQLDelete(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get AllowDirectSQLInsert(): boolean
      • Field Name: AllowDirectSQLInsert
      • Display Name: Allow Direct SQL Insert
      • SQL Data Type: bit
      • Default Value: 0
      • Description: When 1, this entity may be populated by INSERT statements that do not go through BaseEntity.Save() — bulk loads, ETL/integration sync, or rows created as a side effect of a stored procedure. Default 0, meaning every insert is expected to flow through BaseEntity so that record-change tracking, entity actions, validation and cache invalidation all run. This column DECLARES intent for the code paths and tooling that consult it; it does not and cannot prevent anyone from executing SQL. Requires TrackRecordChanges = 0 and TrustServerCacheCompletely = 0, because a direct insert produces neither an audit row nor a cache-invalidation event.

      Returns boolean

    • set AllowDirectSQLInsert(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get AllowDirectSQLUpdate(): boolean
      • Field Name: AllowDirectSQLUpdate
      • Display Name: Allow Direct SQL Update
      • SQL Data Type: bit
      • Default Value: 0
      • Description: When 1, this entity may be modified by UPDATE statements that do not go through BaseEntity.Save() — bulk backfills, integration sync, or maintenance routines. Default 0, meaning every update is expected to flow through BaseEntity so that record-change tracking, entity actions, validation and cache invalidation all run. This column DECLARES intent for the code paths and tooling that consult it; it does not and cannot prevent anyone from executing SQL. Requires TrackRecordChanges = 0 and TrustServerCacheCompletely = 0, because a direct update produces neither an audit row nor a cache-invalidation event.

      Returns boolean

    • set AllowDirectSQLUpdate(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get AllowMultipleSubtypes(): boolean
      • Field Name: AllowMultipleSubtypes
      • Display Name: Allow Multiple Subtypes
      • SQL Data Type: bit
      • Default Value: 0
      • Description: When false (default), child types are disjoint - a record can only be one child type at a time. When true, a record can simultaneously exist as multiple child types (e.g., a Person can be both a Member and a Volunteer).

      Returns boolean

    • set AllowMultipleSubtypes(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get AllowRecordMerge(): boolean
      • Field Name: AllowRecordMerge
      • Display Name: Allow Record Merge
      • SQL Data Type: bit
      • Default Value: 0
      • Description: This field must be turned on in order to enable merging of records for the entity. For AllowRecordMerge to be turned on, AllowDeleteAPI must be set to 1, and DeleteType must be set to Soft

      Returns boolean

    • set AllowRecordMerge(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get AllowUpdateAPI(): boolean
      • Field Name: AllowUpdateAPI
      • Display Name: Allow Update API
      • SQL Data Type: bit
      • Default Value: 0
      • Description: Global flag controlling if updates are allowed for any user, or not. If set to 1, a GraqhQL mutation and stored procedure are created. Permissions are still required to perform the action but if this flag is set to 0, no user will be able to perform the action.

      Returns boolean

    • set AllowUpdateAPI(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get AllowUserSearchAPI(): boolean
      • Field Name: AllowUserSearchAPI
      • Display Name: Allow User Search API
      • SQL Data Type: bit
      • Default Value: 0
      • Description: Enabling this bit will result in search being possible at the API and UI layers

      Returns boolean

    • set AllowUserSearchAPI(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get AuditRecordAccess(): boolean
      • Field Name: AuditRecordAccess
      • Display Name: Audit Record Access
      • SQL Data Type: bit
      • Default Value: 1
      • Description: When set to 1, accessing a record by an end-user will result in an Audit Log record being created

      Returns boolean

    • set AuditRecordAccess(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get AuditViewRuns(): boolean
      • Field Name: AuditViewRuns
      • Display Name: Audit View Runs
      • SQL Data Type: bit
      • Default Value: 1
      • Description: When set to 1, users running a view against this entity will result in an Audit Log record being created.

      Returns boolean

    • set AuditViewRuns(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get AutoRowCountFrequency(): number
      • Field Name: AutoRowCountFrequency
      • Display Name: Auto Row Count Frequency
      • SQL Data Type: int
      • Description: Frequency in hours for automatically performing row counts on this entity. If NULL, automatic row counting is disabled. If greater than 0, schedules recurring SELECT COUNT(*) queries at the specified interval.

      Returns number

    • set AutoRowCountFrequency(value: number): void

      Parameters

      • value: number

      Returns void

    • get AutoUpdateAllowUserSearchAPI(): boolean
      • Field Name: AutoUpdateAllowUserSearchAPI
      • Display Name: Auto Update Allow User Search API
      • SQL Data Type: bit
      • Default Value: 1
      • Description: When true, CodeGen LLM can auto-set AllowUserSearchAPI during code generation runs.

      Returns boolean

    • set AutoUpdateAllowUserSearchAPI(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get AutoUpdateDescription(): boolean
      • Field Name: AutoUpdateDescription
      • Display Name: Auto Update Description
      • SQL Data Type: bit
      • Default Value: 1
      • Description: When set to 1 (default), whenever a description is modified in the underlying view (first choice) or table (second choice), the Description column in the entity definition will be automatically updated. If you never set metadata in the database directly, you can leave this alone. However, if you have metadata set in the database level for description, and you want to provide a DIFFERENT description in this entity definition, turn this bit off and then set the Description field and future CodeGen runs will NOT override the Description field here.

      Returns boolean

    • set AutoUpdateDescription(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get AutoUpdateFullTextSearch(): boolean
      • Field Name: AutoUpdateFullTextSearch
      • Display Name: Auto Update Full Text Search
      • SQL Data Type: bit
      • Default Value: 1
      • Description: When true, CodeGen LLM can auto-configure full-text search settings (FullTextSearchEnabled, catalog, index, function) during code generation runs.

      Returns boolean

    • set AutoUpdateFullTextSearch(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get AutoUpdateSupportsGeoCoding(): boolean
      • Field Name: AutoUpdateSupportsGeoCoding
      • Display Name: Auto Update Supports Geo Coding
      • SQL Data Type: bit
      • Default Value: 1
      • Description: When true (default), CodeGen can automatically set SupportsGeoCoding based on LLM analysis of entity fields. Set to 0 to lock the value and prevent CodeGen from changing it.

      Returns boolean

    • set AutoUpdateSupportsGeoCoding(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get BaseTable(): string
      • Field Name: BaseTable
      • Display Name: Base Table
      • SQL Data Type: nvarchar(255)
      • Description: The underlying database table name for this entity.

      Returns string

    • get BaseViewGenerated(): boolean
      • Field Name: BaseViewGenerated
      • Display Name: Base View Generated
      • SQL Data Type: bit
      • Default Value: 1
      • Description: When set to 0, CodeGen no longer generates a base view for the entity.

      Returns boolean

    • set BaseViewGenerated(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get BoundProvider(): IEntityDataProvider

      The provider actually stored on this instance, or null if none was bound. Unlike ProviderToUse, this does not fall back to the process-wide BaseEntity.Provider. Use it to detect a dropped constructor argument: GetEntityObject(graphProvider) must yield BoundProvider === graphProvider.

      Returns IEntityDataProvider

    • get CanonicalSchemaName(): string
      • Field Name: CanonicalSchemaName
      • Display Name: Canonical Schema Name
      • SQL Data Type: nvarchar(50)

      Returns string

    • get CascadeDeletes(): boolean
      • Field Name: CascadeDeletes
      • Display Name: Cascade Deletes
      • SQL Data Type: bit
      • Default Value: 0
      • Description: When set to 1, the deleted spDelete will pre-process deletion to related entities that have 1:M cardinality with this entity. This does not have effect if spDeleteGenerated = 0

      Returns boolean

    • set CascadeDeletes(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get ClassName(): string
      • Field Name: ClassName
      • Display Name: Class Name
      • SQL Data Type: nvarchar(MAX)
      • Description: Schema-based programmatic class name used for TypeScript entity classes, Zod schemas, and Angular form components. Computed as GetProgrammaticName(GetClassNameSchemaPrefix(SchemaName) + BaseTable + NameSuffix). The prefix is derived from SchemaName (guaranteed unique by SQL Server), not from EntityNamePrefix. For the core __mj schema, the prefix is "MJ"; for all other schemas it is the alphanumeric-sanitized schema name. This prevents cross-schema collisions and aligns with GraphQL type naming in getGraphQLTypeNameBase().

      Returns string

    • get CodeName(): string
      • Field Name: CodeName
      • Display Name: Code Name
      • SQL Data Type: nvarchar(MAX)
      • Description: Schema-based programmatic code name derived from the entity Name. Uses GetClassNameSchemaPrefix(SchemaName) as the prefix, then strips EntityNamePrefix from the Name and removes spaces. For "__mj" schema with entity "MJ: AI Models", this produces "MJAIModels". For entities in other schemas, the sanitized schema name is prepended. Used in GraphQL type generation and internal code references.

      Returns string

    • get Companions(): readonly EntityCompanion<unknown>[]

      The companions registered on this entity, in declaration order.

      Empty for the vast majority of entities. Nothing in the save, load or validation paths does any companion work when this is empty, so the feature costs nothing where it is unused.

      Returns readonly EntityCompanion<unknown>[]

    • get Configuration(): string
      • Field Name: Configuration
      • Display Name: Configuration
      • SQL Data Type: nvarchar(MAX)
      • JSON Type: MJEntityEntity_IEntityConfiguration
      • Description: Optional JSON configuration bag for this entity (shape = IEntityConfiguration). Nested UI.Form holds generated-form chrome: Layout (accordion | left-nav | auto) and AutoLeftNavAt. NULL / omitted keys = today's behavior (accordion; every DisplayInForm relationship is first-class). Expand by adding a property on the interface — no schema change. Anything the engine filters or joins on stays a column; anything the UI or a BaseFormPolicy consumes at render time belongs here.

      Returns string

    • set Configuration(value: string): void

      Parameters

      • value: string

      Returns void

    • get ContextCurrentUser(): UserInfo

      Returns UserInfo

    • set ContextCurrentUser(user: UserInfo): void

      The ContextCurrentUser is a property used to manually set the "current" user for scenarios, primarily on the server side, where the user changes per request. For situations where there is no global CurrentUser in the Metadata.Provider, you MUST set this property to the user you want to use for the current operation. If you used Metadata.GetEntityObject() to get the entity object, this property will be set automatically for you as that method has a parameter that can be provided for the ContextCurrentUser.

      Parameters

      Returns void

    • get CustomResolverAPI(): boolean
      • Field Name: CustomResolverAPI
      • Display Name: Custom Resolver API
      • SQL Data Type: bit
      • Default Value: 0
      • Description: Set to 1 if a custom resolver has been created for the entity.

      Returns boolean

    • set CustomResolverAPI(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get DefaultSkipAsyncValidation(): boolean
      Protected

      Default value for whether async validation should be skipped.

      Returns boolean

      Override this to state a policy explicitly; an explicit override always wins over the inference described below. When the options object passed to Save() includes SkipAsyncValidation, that value takes precedence over both.

      If no subclass overrides this getter, the answer is inferred instead: async validation runs when a subclass has overridden ValidateAsync, and is skipped when none has. Reading the literal true below as "async validation is off unless you find this getter" made every hand-written ValidateAsync a silent no-op — see the note on that method.

    • get DeleteType(): "Hard" | "Soft"
      • Field Name: DeleteType
      • Display Name: Delete Type
      • SQL Data Type: nvarchar(10)
      • Default Value: Hard
      • Value List Type: List
      • Possible Values
        • Hard
        • Soft
      • Description: Hard deletes physically remove rows from the underlying BaseTable. Soft deletes do not remove rows but instead mark the row as deleted by using the special field __mj_DeletedAt which will automatically be added to the entity's basetable by the CodeGen tool.

      Returns "Hard" | "Soft"

    • set DeleteType(value: "Hard" | "Soft"): void

      Parameters

      • value: "Hard" | "Soft"

      Returns void

    • get DetectExternalChanges(): boolean
      • Field Name: DetectExternalChanges
      • Display Name: Detect External Changes
      • SQL Data Type: bit
      • Default Value: 0
      • Description: When set to 1 AND TrackRecordChanges is also 1, the external change detection system will scan this entity for changes made outside the MJ framework (direct SQL, third-party tools, etc.) and replay them through Save() to create proper RecordChange audit entries. Default is 0 (opt-out) because most entities, especially __mj schema metadata tables, are managed by migrations/CodeGen and should not be scanned.

      Returns boolean

    • set DetectExternalChanges(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get Dirty(): boolean

      Returns boolean

    • get DisplayName(): string
      • Field Name: DisplayName
      • Display Name: Display Name
      • SQL Data Type: nvarchar(255)
      • Description: User-friendly display name shown in the Explorer UI and other interfaces. When set, this is used instead of the entity Name for display purposes. Typically contains the entity name without the schema prefix — e.g., "AI Models" when Name is "MJ: AI Models". If NULL, the UI falls back to using the full Name.

      Returns string

    • set DisplayName(value: string): void

      Parameters

      • value: string

      Returns void

    • get EnableFieldLevelSecurity(): boolean
      • Field Name: EnableFieldLevelSecurity
      • Display Name: Enable Field Level Security
      • SQL Data Type: bit
      • Default Value: 0
      • Description: When 1, field-level (column-level) security is enforced for this entity and every enforcement point consults EntityFieldPermission rows. When 0 (the default), field-level security is off entirely and any existing permission rows are retained but inactive. Enabling snapshots the entity's current entity-level permissions into per-field rows, so turning it on changes no behavior until an administrator tightens a field; disabling preserves the rows so re-enabling does not lose the configuration.

      Returns boolean

    • set EnableFieldLevelSecurity(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get EntityInfo(): EntityInfo

      Access to the underlying metadata for the entity object.

      Returns EntityInfo

    • get EntityObjectSubclassImport(): string
      • Field Name: EntityObjectSubclassImport
      • Display Name: Entity Object Subclass Import
      • SQL Data Type: nvarchar(255)
      • Description: Import path for the entity subclass in the TypeScript codebase.

      Returns string

    • set EntityObjectSubclassImport(value: string): void

      Parameters

      • value: string

      Returns void

    • get EntityObjectSubclassName(): string
      • Field Name: EntityObjectSubclassName
      • Display Name: Entity Object Subclass Name
      • SQL Data Type: nvarchar(255)
      • Description: TypeScript class name for the entity subclass in the codebase.

      Returns string

    • set EntityObjectSubclassName(value: string): void

      Parameters

      • value: string

      Returns void

    • get ExternalObjectName(): string
      • Field Name: ExternalObjectName
      • Display Name: External Object Name
      • SQL Data Type: nvarchar(255)
      • Description: Remote object name (table / view / collection) on the external system that backs this entity. Resolved against the data source DefaultSchema/DefaultDatabase when unqualified. Only meaningful when ExternalDataSourceID is set.

      Returns string

    • set ExternalObjectName(value: string): void

      Parameters

      • value: string

      Returns void

    • get Fields(): EntityField[]

      Returns EntityField[]

    • get FirstPrimaryKey(): EntityField

      Helper method to return just the first Primary Key

      Returns EntityField

    • get FullTextCatalogGenerated(): boolean
      • Field Name: FullTextCatalogGenerated
      • Display Name: Full Text Catalog Generated
      • SQL Data Type: bit
      • Default Value: 1
      • Description: Indicates if the full-text catalog was auto-generated by CodeGen.

      Returns boolean

    • set FullTextCatalogGenerated(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get FullTextIndexGenerated(): boolean
      • Field Name: FullTextIndexGenerated
      • Display Name: Full Text Index Generated
      • SQL Data Type: bit
      • Default Value: 1
      • Description: Indicates if the full-text index was auto-generated by CodeGen.

      Returns boolean

    • set FullTextIndexGenerated(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get FullTextSearchEnabled(): boolean
      • Field Name: FullTextSearchEnabled
      • Display Name: Full Text Search Enabled
      • SQL Data Type: bit
      • Default Value: 0
      • Description: Whether full-text search indexing is enabled for this entity.

      Returns boolean

    • set FullTextSearchEnabled(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get FullTextSearchFunction(): string
      • Field Name: FullTextSearchFunction
      • Display Name: Full Text Search Function
      • SQL Data Type: nvarchar(255)
      • Description: Name of the function used for full-text searching this entity.

      Returns string

    • set FullTextSearchFunction(value: string): void

      Parameters

      • value: string

      Returns void

    • get FullTextSearchFunctionGenerated(): boolean
      • Field Name: FullTextSearchFunctionGenerated
      • Display Name: Full Text Search Function Generated
      • SQL Data Type: bit
      • Default Value: 1
      • Description: Indicates if the search function was auto-generated by CodeGen.

      Returns boolean

    • set FullTextSearchFunctionGenerated(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get GeneratedBaseViewName(): string
      • Field Name: GeneratedBaseViewName
      • Display Name: Generated Base View Name
      • SQL Data Type: nvarchar(255)
      • Description: When set, CodeGen generates the entity's full base view under THIS name instead of BaseView, and the application owns BaseView — which is expected to wrap it (SELECT g.*, FROM g). This gives an entity a custom base view WITHOUT inheriting the generated SQL: related-entity display joins, geo columns and recursive root-ID columns keep regenerating underneath, so a foreign key added later still appears. NULL (the default, and every pre-existing row) means the previous all-or-nothing behaviour: BaseViewGenerated alone decides whether CodeGen writes BaseView, and there is no second view. BaseView remains the public surface — entity field discovery, permissions and the generated CRUD procedures all target it. SQL SERVER ONLY: layering relies on sp_refreshview to re-resolve the application-owned outer view's SELECT * against a regenerated inner view. PostgreSQL freezes a view's column list at creation and has no refresh equivalent, so CodeGen rejects this column on PostgreSQL rather than let the outer view go silently stale.

      Returns string

    • set GeneratedBaseViewName(value: string): void

      Parameters

      • value: string

      Returns void

    • get HasCompanions(): boolean

      Whether this entity has any registered companions.

      Used as the fast guard on the hot paths — a single boolean check keeps single-record saves on exactly the code path they took before companions existed.

      Returns boolean

    • get IncludeInAPI(): boolean
      • Field Name: IncludeInAPI
      • Display Name: Include In API
      • SQL Data Type: bit
      • Default Value: 0
      • Description: If set to 0, the entity will not be available at all in the GraphQL API or the object model.

      Returns boolean

    • set IncludeInAPI(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get ISAChild(): BaseEntity<unknown>

      Returns the child entity in the IS-A composition chain, or null if this entity has no child record, hasn't been loaded yet, or is an overlapping subtype parent (use ISAChildren instead for overlapping parents).

      Example: For a MeetingEntity where a Webinar record exists with the same PK, ISAChild returns the WebinarEntity instance.

      Returns BaseEntity<unknown>

    • get ISAChildren(): { entityName: string }[]

      For overlapping subtype parents (AllowMultipleSubtypes = true), returns the list of child entity type names that have records for this PK. For disjoint parents or non-parent entities, returns null (use ISAChild instead).

      Example: For a PersonEntity with AllowMultipleSubtypes=true, might return [{entityName: 'Members'}, {entityName: 'Volunteers'}, {entityName: 'Speakers'}].

      Returns { entityName: string }[]

    • get ISAParent(): BaseEntity<unknown>

      Returns the parent entity in the IS-A composition chain, or null if this entity is not an IS-A child type.

      Example: For a MeetingEntity that IS-A ProductEntity, ISAParent returns the ProductEntity instance.

      Named with ISA prefix to avoid collision with generated entity properties (many entities have a Parent string column in the database).

      Returns BaseEntity<unknown>

    • get ISAParentEntity(): BaseEntity<unknown>

      Returns BaseEntity<unknown>

      Use ISAParent instead. Kept for backward compatibility.

    • get IsBusy(): boolean

      Returns true if any operation (Save, Delete, or Load) is currently in progress. This is a convenience property that combines IsSaving, IsDeleting, and IsLoading. Useful for disabling UI elements when any database operation is happening.

      Returns boolean

    • get IsDeleting(): boolean

      Returns true if a Delete operation is currently in progress. This is useful for UI components to show loading indicators or disable buttons while deleting.

      Returns boolean

    • get IsLoading(): boolean

      Returns true if a Load operation is currently in progress. This is useful for UI components to show loading indicators while data is being fetched.

      Returns boolean

    • get IsSaved(): boolean

      Returns true if the record has been saved to the database, false otherwise. This is a useful property to check to determine if the record is a "New Record" or an existing one.

      Returns boolean

    • get IsSaving(): boolean

      Returns true if a Save operation is currently in progress. This is useful for UI components to show loading indicators or disable buttons while saving.

      Returns boolean

    • get LatestResult(): BaseEntityResult

      Returns the most recent result from the result history. If there are no results in the history, this method will return null.

      Returns BaseEntityResult

    • get LeafEntity(): BaseEntity

      Returns the leaf (most-derived) entity in the IS-A chain, walking downward through child references. Returns this if no child exists.

      For overlapping subtype parents (AllowMultipleSubtypes = true), returns this because there is no single child chain to follow — the parent is the leaf from its own perspective.

      Returns BaseEntity

    • get Name(): string
      • Field Name: Name
      • Display Name: Name
      • SQL Data Type: nvarchar(255)
      • Description: The canonical, unique name for this entity. For entities in schemas with an EntityNamePrefix configured (e.g., "MJ: " for the core schema), the Name includes the prefix: "MJ: AI Models", "MJ: Users", etc. This is the value used in GetEntityObject(), RunView({ EntityName }), and

      Returns string

      decorators. The DisplayName column provides the shorter, UI-friendly alternative without the prefix.

    • set Name(value: string): void

      Parameters

      • value: string

      Returns void

    • get PreferredCommunicationField(): string
      • Field Name: PreferredCommunicationField
      • Display Name: Preferred Communication Field
      • SQL Data Type: nvarchar(255)
      • Description: Used to specify a field within the entity that in turn contains the field name that will be used for record-level communication preferences. For example in a hypothetical entity called Contacts, say there is a field called PreferredComm and that field had possible values of Email1, SMS, and Phone, and those value in turn corresponded to field names in the entity. Each record in the Contacts entity could have a specific preference for which field would be used for communication. The MJ Communication Framework will use this information when available, as a priority ahead of the data in the Entity Communication Fields entity which is entity-level and not record-level.

      Returns string

    • set PreferredCommunicationField(value: string): void

      Parameters

      • value: string

      Returns void

    • get PrimaryKey(): CompositeKey

      Returns the primary key for the record. The CompositeKey class is a multi-valued key that can have any number of key/value pairs within it. Always traverse the full set of key/value pairs to get the full primary key for the record.

      Returns CompositeKey

    • get PrimaryKeys(): EntityField[]

      Returns an array of all primary key fields for the entity. If the entity has a composite primary key, this method will return an array of all primary key fields. If the entity has a single primary key, this method will return an array with a single field in it.

      Returns EntityField[]

    • get ProviderToUse(): IEntityDataProvider

      Returns this provider to be used for a given instance of a BaseEntity derived subclass. If the provider is not set, the BaseEntity.Provider is returned.

      Returns IEntityDataProvider

    • get RecordChanges(): Promise<RecordChange[]>

      Returns a list of changes made to this record, over time. Only works if TrackRecordChanges bit set to 1 on the entity you're working with.

      Returns Promise<RecordChange[]>

    • get RecordLoaded(): boolean

      Returns true if the record has been loaded from the database, false otherwise. This is useful to check to see if the record is in a "New Record" state or not.

      Returns boolean

    • get RelationshipDefaultDisplayType(): "Search" | "Dropdown"
      • Field Name: RelationshipDefaultDisplayType
      • Display Name: Relationship Default Display Type
      • SQL Data Type: nvarchar(20)
      • Default Value: Search
      • Value List Type: List
      • Possible Values
        • Dropdown
        • Search
      • Description: When another entity links to this entity with a foreign key, this is the default component type that will be used in the UI. CodeGen will populate the RelatedEntityDisplayType column in the Entity Fields entity with whatever is provided here whenever a new foreign key is detected by CodeGen. The selection can be overridden on a per-foreign-key basis in each row of the Entity Fields entity.

      Returns "Search" | "Dropdown"

    • set RelationshipDefaultDisplayType(value: "Search" | "Dropdown"): void

      Parameters

      • value: "Search" | "Dropdown"

      Returns void

    • get RestoreContext(): RestoreContext

      Returns the active restore context for the next save, if any.

      Read by the data provider when generating the RecordChange SQL: when non-null, the resulting RecordChange row is written with Source='Restore', RestoredFromID = SourceChangeID, and RestoreReason = Reason. Returns null for ordinary saves.

      Returns RestoreContext

    • get ResultHistory(): BaseEntityResult[]

      The result history shows the history of the attempted transactions (Save and Delete) for this particular entity object. This is useful for tracking the results of operations on the entity object.

      Returns BaseEntityResult[]

    • get RootEntity(): BaseEntity

      Returns the root (least-derived) entity in the IS-A chain, walking upward through parent references. Returns this if no parent exists.

      Returns BaseEntity

    • get RowsToPackSampleCount(): number
      • Field Name: RowsToPackSampleCount
      • Display Name: Rows To Pack Sample Count
      • SQL Data Type: int
      • Default Value: 0
      • Description: The number of rows to pack when RowsToPackWithSchema is set to Sample, based on the designated sampling method. Defaults to 0.

      Returns number

    • set RowsToPackSampleCount(value: number): void

      Parameters

      • value: number

      Returns void

    • get RowsToPackSampleMethod(): "bottom n" | "random" | "top n"
      • Field Name: RowsToPackSampleMethod
      • Display Name: Rows To Pack Sample Method
      • SQL Data Type: nvarchar(20)
      • Default Value: random
      • Value List Type: List
      • Possible Values
        • bottom n
        • random
        • top n
      • Description: Defines the sampling method for row packing when RowsToPackWithSchema is set to Sample. Options include random, top n, and bottom n. Defaults to random.

      Returns "bottom n" | "random" | "top n"

    • set RowsToPackSampleMethod(value: "bottom n" | "random" | "top n"): void

      Parameters

      • value: "bottom n" | "random" | "top n"

      Returns void

    • get RowsToPackSampleOrder(): string
      • Field Name: RowsToPackSampleOrder
      • Display Name: Rows To Pack Sample Order
      • SQL Data Type: nvarchar(MAX)
      • Description: An optional ORDER BY clause for row packing when RowsToPackWithSchema is set to Sample. Allows custom ordering for selected entity data when using top n and bottom n.

      Returns string

    • set RowsToPackSampleOrder(value: string): void

      Parameters

      • value: string

      Returns void

    • get RowsToPackWithSchema(): "None" | "All" | "Sample"
      • Field Name: RowsToPackWithSchema
      • Display Name: Rows To Pack With Schema
      • SQL Data Type: nvarchar(20)
      • Default Value: None
      • Value List Type: List
      • Possible Values
        • All
        • None
        • Sample
      • Description: Determines how entity rows should be packaged for external use. Options include None, Sample, and All. Defaults to None.

      Returns "None" | "All" | "Sample"

    • set RowsToPackWithSchema(value: "None" | "All" | "Sample"): void

      Parameters

      • value: "None" | "All" | "Sample"

      Returns void

    • get RunQueryProviderToUse(): IRunQueryProvider

      Returns the RunQueryProvider to be used for a given instance of a BaseEntity derived subclass.

      Returns IRunQueryProvider

    • get RunViewProviderToUse(): IRunViewProvider

      Returns the RunViewProvider to be used for a given instance of a BaseEntity derived subclass.

      Returns IRunViewProvider

    • get SchemaName(): string
      • Field Name: SchemaName
      • Display Name: Schema Name
      • SQL Data Type: nvarchar(255)
      • Default Value: dbo
      • Description: Database schema containing this entity's table and view.

      Returns string

    • get ScopeDefault(): string
      • Field Name: ScopeDefault
      • Display Name: Scope Default
      • SQL Data Type: nvarchar(100)
      • Description: Optional, comma-delimited string indicating the default scope for entity visibility. Options include Users, Admins, AI, and All. Defaults to All when NULL. This is used for simple defaults for filtering entity visibility, not security enforcement.

      Returns string

    • set ScopeDefault(value: string): void

      Parameters

      • value: string

      Returns void

    • get SkipEmbeddings(): boolean

      Returns boolean

    • set SkipEmbeddings(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get spCreateGenerated(): boolean
      • Field Name: spCreateGenerated
      • Display Name: Create Procedure Generated
      • SQL Data Type: bit
      • Default Value: 1
      • Description: Indicates if the create procedure was auto-generated by CodeGen.

      Returns boolean

    • set spCreateGenerated(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get spDeleteGenerated(): boolean
      • Field Name: spDeleteGenerated
      • Display Name: Delete Procedure Generated
      • SQL Data Type: bit
      • Default Value: 1
      • Description: Indicates if the delete procedure was auto-generated by CodeGen.

      Returns boolean

    • set spDeleteGenerated(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get spMatch(): string
      • Field Name: spMatch
      • Display Name: Match Stored Procedure
      • SQL Data Type: nvarchar(255)
      • Description: When specified, this stored procedure is used to find matching records in this particular entity. The convention is to pass in the primary key(s) columns for the given entity to the procedure and the return will be zero to many rows where there is a column for each primary key field(s) and a ProbabilityScore (numeric(1,12)) column that has a 0 to 1 value of the probability of a match.

      Returns string

    • set spMatch(value: string): void

      Parameters

      • value: string

      Returns void

    • get spUpdateGenerated(): boolean
      • Field Name: spUpdateGenerated
      • Display Name: Update Procedure Generated
      • SQL Data Type: bit
      • Default Value: 1
      • Description: Indicates if the update procedure was auto-generated by CodeGen.

      Returns boolean

    • set spUpdateGenerated(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get Status(): "Active" | "Disabled" | "Deprecated"
      • Field Name: Status
      • Display Name: Status
      • SQL Data Type: nvarchar(25)
      • Default Value: Active
      • Value List Type: List
      • Possible Values
        • Active
        • Deprecated
        • Disabled
      • Description: Status of the entity. Active: fully functional; Deprecated: functional but generates console warnings when used; Disabled: not available for use even though metadata and physical table remain.

      Returns "Active" | "Disabled" | "Deprecated"

    • set Status(value: "Active" | "Disabled" | "Deprecated"): void

      Parameters

      • value: "Active" | "Disabled" | "Deprecated"

      Returns void

    • get SubtypeSelector(): string
      • Field Name: SubtypeSelector
      • Display Name: Subtype Selector
      • SQL Data Type: nvarchar(MAX)
      • JSON Type: MJEntityEntity_IEntitySubtypeSelectorConfig
      • Description: Optional JSON configuration specifying the declarative subtype selector for this entity (shape = IEntitySubtypeSelectorConfig). Path is a dotted foreign-key dereference path ending at a column containing the target subtype entity name (e.g. "ProductID.ProductTypeID.OrderLineExtensionEntity"). Read by BaseEntity.ResolveSubtypeEntityName() as a fallback when no runtime EntitySubtypeResolver is registered, and by offline tooling like Loom and CodeGen to determine conditional IsA child entities. NULL means no declarative subtype selector is configured.

      Returns string

    • set SubtypeSelector(value: string): void

      Parameters

      • value: string

      Returns void

    • get SupportsGeoCoding(): boolean
      • Field Name: SupportsGeoCoding
      • Display Name: Supports Geo Coding
      • SQL Data Type: bit
      • Default Value: 0
      • Description: When true, CodeGen generates geo-aware subclass code, adds __mj_Latitude/__mj_Longitude virtual fields to the base view, and the UI shows a map view toggle. Auto-set by CodeGen when LLM detects geo-capable fields (address, lat/lng, etc.).

      Returns boolean

    • set SupportsGeoCoding(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get TrackRecordChanges(): boolean
      • Field Name: TrackRecordChanges
      • Display Name: Track Record Changes
      • SQL Data Type: bit
      • Default Value: 1
      • Description: When set to 1, changes made via the MemberJunction architecture will result in tracking records being created in the RecordChange table. In addition, when turned on CodeGen will ensure that your table has two fields: __mj_CreatedAt and __mj_UpdatedAt which are special fields used in conjunction with the RecordChange table to track changes to rows in your entity.

      Returns boolean

    • set TrackRecordChanges(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get TransactionGroup(): TransactionGroupBase

      Transaction Groups are used to group multiple transactions into a single ATOMic transaction in a database. They are also useful even in situations with ATOMicity is less important but you want to submit a group of changes to the API server in a single network call.

      Returns TransactionGroupBase

    • set TransactionGroup(group: TransactionGroupBase): void

      Parameters

      Returns void

    • get TrustServerCacheCompletely(): boolean
      • Field Name: TrustServerCacheCompletely
      • Display Name: Trust Server Cache Completely
      • SQL Data Type: bit
      • Default Value: 1
      • Description: When true (default), the server-side RunView cache will store and return cached results for this entity, trusting that all mutations flow through BaseEntity.Save() which fires cache invalidation events. Set to false for entities whose rows are created as side-effects of other operations via raw SQL (e.g., Record Changes created by spCreateRecordChange_Internal), since those inserts bypass BaseEntity and never trigger cache invalidation.

      Returns boolean

    • set TrustServerCacheCompletely(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get UserFormGenerated(): boolean
      • Field Name: UserFormGenerated
      • Display Name: User Form Generated
      • SQL Data Type: bit
      • Default Value: 1
      • Description: Indicates if the default user form was auto-generated for this entity.

      Returns boolean

    • set UserFormGenerated(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get UserViewMaxRows(): number
      • Field Name: UserViewMaxRows
      • Display Name: User View Max Rows
      • SQL Data Type: int
      • Default Value: 1000
      • Description: Maximum number of rows to return in user-created views for this entity.

      Returns number

    • set UserViewMaxRows(value: number): void

      Parameters

      • value: number

      Returns void

    • get Vectors(): Map<string, number[]>

      Utility storage for vector embeddings that represent the active record. Each string in the Map can be any unique key relative to the object so you can use this to track vectors associated with

      Returns Map<string, number[]>

    • get BaseEventCode(): string

      When a BaseEntity class raises an event with MJGlobal, the eventCode property is set to this value. This is used to identify events that are raised by BaseEntity objects. Any MJGlobal event that is raised by a BaseEntity class will use a BaseEntityEvent type as the args parameter

      Returns string

    • get Provider(): IEntityDataProvider

      Static property to get/set the IEntityDataProvider that is used by all BaseEntity objects. This is a global setting that is used by all BaseEntity objects. It can be overriden for a given BaseEntity object instance by passing in a provider to the constructor of the BaseEntity object. Typically, a provider will pass itself into BaseEntity objects it creates to create a tight coupling between the provider and the BaseEntity objects it creates. This allows multiple concurrent connections to exist in the same process space without interfering with each other.

      Returns IEntityDataProvider

    • set Provider(value: IEntityDataProvider): void

      Parameters

      Returns void

    Methods

    • Field-level security on the INSERT path: marks the fields this user may not supply so the save omits them and each column takes its database default.

      This never rejects, and that is deliberate. Rejecting would be inconsistent with the read path (a denied field is simply absent, not an error) and would leak information — an error naming Salary confirms the field exists and is restricted, which the ambiguous denial wording exists to prevent. Silently defaulting is also what an unrestricted user gets by leaving the field blank, so a restricted user creating a record ends up with the same record SHAPE rather than a failure.

      The cost is that a user who supplies a value for a create-denied field gets no feedback that it was dropped, which is why the drop is logged and why the admin UI should not render the field at all.

      Runs on every save (clearing prior marks first) because the answer depends on the acting user, and one entity object can be saved by different users over its lifetime.

      Returns void

    • IS-A PROMOTION (#3825): binds this NEW child record to an EXISTING parent row, so saving it ADDS a subtype to a person/org/product that already exists instead of trying to create a duplicate parent.

      Before this existed the operation was impossible: NewRecord() always starts a fresh parent chain, so "this existing Person is now also an Applicant" INSERTed a second Person and collided with the existing primary key (or, with parent fields unset, failed the parent's NOT NULL validation as if it were brand new). Discovery ran the other way only — a loaded parent finds its existing child — and promotion is the normal case in a multi-app install, where a shared entity like Person accumulates subtypes owned by different applications.

      What it does, in the existing machinery rather than beside it:

      1. LOADS the parent chain by the supplied key (InnerLoad, which also hydrates any grandparents from the same row). A loaded parent saves as an UPDATE, which is the whole trick — the chain save that already runs parent-first now updates the existing row and INSERTs only this child.
      2. Mirrors the shared primary key into this child's local fields, restoring _NeverSet exactly as NewRecord()'s adoption path does, so the ReadOnly mirror stays writable for the rest of the lifecycle.

      Everything else is deliberately UNTOUCHED: field routing still sends parent-held values to the (now loaded) parent, permissions and validation run at every level, and EnforceDisjointSubtype still refuses a second subtype where the parent forbids overlap. If loading the parent discovers an existing child of ANOTHER subtype, the chain save is unaffected — parent saves run with IsParentEntitySave, which bypasses leaf delegation.

      Call AFTER NewRecord() and BEFORE Save():

      const applicant = await md.GetEntityObject<ApplicantEntity>('Applicants', contextUser);
      applicant.NewRecord();
      if (!await applicant.AttachToParent(CompositeKey.FromID(personId))) {
      // no such parent row — decide whether to create a fresh chain instead
      }
      applicant.Set('CompanyID', companyId); // child-held fields as usual
      await applicant.Save(); // Person UPDATEd, Applicant INSERTed, one transaction

      Parameters

      • parentKey: CompositeKey

        Primary key of the EXISTING parent row to promote.

      Returns Promise<boolean>

      true when the parent loaded and this record is now bound to it; false when no parent row exists under that key (this record is left exactly as it was — still a fresh chain — so the caller can choose to save it as one).

      When this entity is not an IS-A child type, or has already been saved — promotion is a decision about what a NEW record IS, not an edit to an existing one.

    • Called before an Action is executed by the AI Engine This is intended to be overriden by subclass as needed, these methods called at the right time by the execution context

      Parameters

      Returns Promise<boolean>

    • Bind this instance to a provider after construction.

      Rule (ORM, not just metadata-sync): every DB read and write on this instance — Save, Load, Delete, RunView, GetEntityObject of children/embeds, lookups, RecordGeoCode — MUST use this provider. Mixing another provider (especially the process-wide host) into the same record graph is a deadlock: a child FK waits on an uncommitted parent on another connection.

      ProviderBase.GetEntityObject always calls this so a subclass that declares constructor(Entity: EntityInfo) and drops the second ClassFactory argument cannot silently run on the global host.

      Parameters

      Returns void

    • Builds the ordered unit of work for deleting this record and everything its companions contribute.

      Companions contribute first: children hold foreign keys pointing at the row that is about to disappear, so they must be removed before it.

      Returns EntitySavePlan

      The plan.

    • Builds the ordered unit of work for saving this record and everything its companions contribute.

      The root node comes first — children need the parent's primary key, and on a create it does not exist until the parent row is inserted.

      Parameters

      • OptionalincludeRoot: boolean

        Whether to include this record's own save. False when the caller has already persisted the root by other means.

      • OptionalsaveOptions: EntitySaveOptions

        The caller's save options, forwarded to each companion so it can honor flags that change what counts as work (IgnoreDirtyState, most importantly — a companion that skips clean children must not skip them when the caller demanded a full write-out).

      Returns EntitySavePlan

      The plan. A NodeCount of 1 means there is no graph and the caller should take the ordinary single-record path.

    • Cascade-deletes an IS-A child record when the parent entity has CascadeDeletes enabled. Loads the child entity, then deletes it through the normal IS-A chain. The child's delete will cascade further down if it also has children and CascadeDeletes.

      Parameters

      • childCheck: { ChildEntityName: string; HasChildren: boolean }
      • parentOptions: EntityDeleteOptions

      Returns Promise<boolean>

    • Field-level security on the write path: rejects a save that modifies a field this user has no update permission on.

      ENFORCEMENT LAYER — read this before treating it as the security boundary. BaseEntity also runs in the browser, where this guard is trivially bypassable. The AUTHORITATIVE check is the server-side execution of this same code: the MJServer mutation resolver re-instantiates the entity and re-runs Save on the server, where the client cannot reach it. The client-side occurrence is UX and defense-in-depth — fail fast with a clear message before a network round-trip — and must never be relied on alone.

      UPDATE rejects; CREATE does not — see ApplyFieldLevelCreateSuppression.

      Note this checks DIRTY fields only. CLIENT-side that is safe on its own: nothing ever nulls a restricted value in memory, so a field the user cannot see was never loaded as null, is not dirty, and an unrelated edit saves cleanly with the restricted column keeping its stored value.

      SERVER-side, dirty-only is safe only because ResolverBase.UpdateRecord guarantees the entity was hydrated FROM THE DATABASE on every FLS entity. Two distinct resolver behaviours carry that premise, and BOTH are load-bearing:

      1. StripDeniedReadFieldsFromClientInput removes client-sent values for fields the caller cannot READ, which SetMany would otherwise make genuinely dirty with fabricated data.
      2. entityInfo.EnableFieldLevelSecurity forces the truth-load branch, so the entity's non-dirty baseline is the real stored row rather than the client's OldValues___.

      (2) is not redundant with (1). A value arriving through LoadFromData is recorded by the EntityField setter as the field's INITIAL value, so it is not dirty — and this check would never see it, while GenerateSaveSQL sends it anyway (it filters on NotLoaded, never on Dirty). Without the forced truth-load, a caller with Read Allow + Update Deny — the canonical FLS configuration, and one that leaves (1) with nothing to strip — could write an update-denied field just by pinning its value in OldValues___ and never naming it in the mutation. If you are considering relaxing that branch condition, this check is what breaks.

      The refusal names the missing permission when the caller can READ the field, and falls back to the ambiguous "does not exist or you do not have access" wording when they cannot. See FieldSecurityWriteDenialMessage for why that split discloses nothing.

      Returns void

    • Checks if this entity has any child records in IS-A child entity tables. Used for parent delete protection — a parent record cannot be deleted while child type records referencing it still exist.

      Returns Promise<{ ChildEntityName: string; HasChildren: boolean }>

      Object with HasChildren flag and the name of the child entity found

    • Utility method that returns true if the given permission being checked is enabled for the current user, and false if not.

      Parameters

      Returns boolean

    • Clears any pending restore context. Safe to call when no context is set. Recommended after Save() returns so a subsequent ordinary save isn't accidentally tagged as a restore.

      Returns void

    • This method MUST be called right after the class is instantiated to provide an async/await pair for any asynchronous operations a given entity needs to do when it is first created/configured. When you call Metadata/Provider GetEntityObject() this is done automatically for you. In nearly all cases you should go through GetEntityObject() anyway and not ever directly instantiate a BaseEntity derived class.

      Parameters

      Returns Promise<void>

    • Builds a related entity the way GetEntityObject does, minus NewRecord / Load. Used by EmbeddedRecord so construction can thread a cycle-detection set.

      Type Parameters

      • T extends BaseEntity<unknown>

        The entity type to construct.

      Parameters

      • entityName: string

        Metadata entity name.

      • visited: Set<string>

        Cycle guard, forwarded into the new instance's own embeddeds.

      Returns Promise<T>

    • This method will copy the values from the other entity object into the current one. This is useful for things like cloning a record. This method will ONLY copy values for fields that exist in the current entity object. If the other object has fields that don't exist in the current object, they will be ignored.

      Parameters

      • other: BaseEntity

        the other entity object to copy values from

      • OptionalincludePrimaryKeys: boolean

        if true, the primary keys will be copied as well, if false, they will be ignored, defaults to false and generally you want to leave it that way

      • OptionalreplaceOldValues: boolean

        if true, the old values of the fields will be reset to the values provided in the other parameter, if false, they will be left alone, defaults to false and generally you want to leave it that way

      Returns boolean

    • Declares a typed child collection on this entity and registers it as a companion.

      This is the entry point for composite entities. Call it from a field initialiser on a shared (client + server) subclass so both tiers see the collection — a declaration that exists only in a server-side class makes the collection invisible to the browser, which is exactly the limitation this feature removes.

      Type Parameters

      Parameters

      Returns RelatedRecordCollection<TChild>

      The registered collection.

      public readonly Lines = this.DeclareRelatedRecords<OrderLineEntity>({
      Name: 'Lines',
      ChildEntity: 'MJ_BizApps_Orders: Order Lines',
      ForeignKey: 'OrderHeaderID',
      OrderBy: 'LineNumber ASC',
      Sequence: { Field: 'LineNumber', From: 1 },
      });
    • This method deletes a record from the database. You must call Load() first in order to load the context of the record you are deleting.

      Debounces multiple calls so that if Delete() is called again while a delete is in progress, the second call will simply receive the same result as the first.

      Parameters

      Returns Promise<boolean>

      Promise

    • In the BaseEntity class this method is not implemented. This method shoudl be implemented only in server-side sub-classes only by calling AIEngine or other methods to generate embeddings for a given piece of text provided. Subclasses that override this method to implement embedding support should also override

      Parameters

      • textToEmbed: string

      Returns Promise<SimpleEmbeddingResult>

      SupportsEmbedTextLocal and return true

    • Enforces disjoint subtype constraint during IS-A child entity creation. A parent record can only be ONE child type at a time. Checks all sibling child types (excluding self) for records with the same PK value. Throws if a sibling child record is found.

      Only called when the parent entity has AllowMultipleSubtypes = false (default). When AllowMultipleSubtypes = true, this check is skipped entirely, allowing overlapping subtypes (e.g., a Person can be both a Member and a Volunteer).

      Only runs on Database providers — client-side (Network/GraphQL) skips this because the server-side save will perform the check authoritatively.

      Returns Promise<void>

    • Returns a promise that resolves when the current Delete operation completes. If no Delete operation is in progress, resolves immediately.

      This is useful when you need to ensure a record is deleted before performing cleanup operations or navigating away from a view.

      Returns Promise<void>

      // Ensure any in-progress delete is complete before proceeding
      await entity.EnsureDeleteComplete();
      // Now safe to navigate away or perform cleanup
      navigateToList();
    • Create-safe prospective counterpart to InitializeChildEntity. Unlike createAndLinkChildEntity, does NOT unlink when InnerLoad finds no row — that is the create case. Idempotent. Defaults to ResolveSubtypeEntityName() when no name is passed.

      Parameters

      • OptionalentityName: string

        Optional explicit child entity name. If omitted, resolved via ResolveSubtypeEntityName().

      Returns Promise<BaseEntity<unknown>>

      The linked child BaseEntity, or null if no subtype applies.

    • Returns a promise that resolves when the current Load operation completes. If no Load operation is in progress, resolves immediately.

      This is useful when you need to ensure data is loaded before accessing entity properties or performing operations that depend on loaded data.

      Returns Promise<void>

      // Ensure any in-progress load is complete before proceeding
      await entity.EnsureLoadComplete();
      // Now safe to access entity data
      console.log(entity.Name);
    • Returns a promise that resolves when the current Save operation completes. If no Save operation is in progress, resolves immediately.

      This is useful when you need to ensure data is persisted before performing a dependent operation, or when coordinating between multiple components that might trigger saves.

      Returns Promise<void>

      // Ensure any in-progress save is complete before proceeding
      await entity.EnsureSaveComplete();
      // Now safe to perform operations that depend on the saved state
      await someOperationThatNeedsSavedData(entity);
    • True when any of the named fields exists on this entity and its current value differs from the last loaded or saved value.

      This is the boolean form of GetFieldByName(name)?.Dirty === true. Prefer it at call sites that only care whether a column has been edited — pricing, validation, and "did the user type this" gates — so they do not repeat the optional-chain and do not treat a missing field as a distinct third state.

      Semantics:

      • Unknown or blank names return false. They are not dirty; they are absent. Callers that must distinguish "no such field" from "field is clean" should use GetFieldByName and inspect the result.
      • Names are case-insensitive and trimmed, matching GetFieldByName.
      • Read-only fields are never dirty, even if their value was overwritten internally.
      • Multiple names are OR'd. FieldIsDirty('UnitPrice', 'ProductPriceID') is true if either field has been edited. An empty rest list is a single-field check.

      Parameters

      • fieldName: string

        First field to test. A missing/blank name contributes false.

      • ...more: string[]

        Additional field names, each OR'd with the first.

      Returns boolean

      true if at least one named field exists and is dirty; otherwise false.

      // Single field
      if (line.FieldIsDirty('UnitPrice')) { ... }

      // Either money column was edited
      if (line.FieldIsDirty('UnitPrice', 'ProductPriceID')) { ... }
    • Strongly-typed wrapper for the SetMany method.

      Type Parameters

      • K extends AnyZodObject

      Parameters

      • data: unknown
      • Optionalschema: TypeOf<K>

        the zod schema to validate the data against

      Returns boolean

      data - the data to set on the entity object

    • Generates a vector embedding for a single text field using AI engine. Only generates embeddings for new records or when the source field has changed. Stores both the vector embedding and the model ID used to generate it.

      Parameters

      • field: EntityField

        The EntityField containing the text to embed

      • vectorField: EntityField

        The EntityField to store the generated vector embedding (as JSON string)

      • modelField: EntityField

        The EntityField to store the ID of the AI model used

      Returns Promise<boolean>

      Promise that resolves to true if embedding was generated successfully, false otherwise

    • Generates a vector embedding for a single text field identified by field name. Retrieves the field objects and delegates to GenerateEmbedding method.

      Parameters

      • fieldName: string

        Name of the text field to generate embedding from

      • vectorFieldName: string

        Name of the field to store the vector embedding

      • modelFieldName: string

        Name of the field to store the model ID used for embedding

      Returns Promise<boolean>

      Promise that resolves to true if embedding was generated successfully, false otherwise

    • Generates vector embeddings for multiple text fields using EntityField objects. Processes fields in parallel for better performance.

      Parameters

      • fields: { field: EntityField; modelField: EntityField; vectorField: EntityField }[]

        Array of field configurations with EntityField objects for source, vector, and model fields

      Returns Promise<boolean>

      Promise that resolves to true if all embeddings were generated successfully, false if any failed

    • Generates vector embeddings for multiple text fields by their field names. Processes fields in parallel for better performance.

      Parameters

      • fields: { fieldName: string; modelFieldName: string; vectorFieldName: string }[]

        Array of field configurations specifying source text field, target vector field, and model ID field names

      Returns Promise<boolean>

      Promise that resolves to true if all embeddings were generated successfully, false if any failed

    • Parameters

      • FieldName: string

      Returns any

    • NOTE: Do not call this method directly. Use the To method instead

      Utility method to create an object and return it with properties in the newly created and returned object for each field in the entity object. This is useful for scenarios where you need to be able to persist the data in a format to send to a network call, save to a file or database, etc. This method will return an object with properties that match the field names of the entity object.

      Parameters

      • OptionaloldValues: boolean

        When set to true, the old values of the fields will be returned instead of the current values.

      • OptionalonlyDirtyFields: boolean

        When set to true, only the fields that are dirty will be returned.

      Returns any

    • Retrieves all ancestor records in the hierarchy from the top-level root down to this record using a single RunView query.

      Type Parameters

      Parameters

      • OptionalparentFieldName: string

        Optional recursive foreign key field name (defaults to 'ParentID' or the first recursive FK found).

      Returns Promise<T[]>

      Array of ancestor entity instances ordered from root down to parent.

    • Returns a partial object that contains only the fields that have changed since the last time the record was saved. This is useful for scenarios where you want to send only the changes to the server or to a client. It is also helpful for quickly finding the fields that are "dirty".

      Returns Partial<T>

    • Retrieves all direct child records of this record using a single RunView query.

      Type Parameters

      Parameters

      • OptionalparentFieldName: string

        Optional recursive foreign key field name (defaults to 'ParentID' or the first recursive FK found).

      Returns Promise<T[]>

      Array of direct child entity instances.

    • This utility method generates a completely new object that has properties that map to the fields and values in the entity at the time it is called. It is a copy, NOT a link, so any changes made to the object after calling this method will NOT be reflected in the object that is returned. This is useful for things like sending data to a client, or for use in a view model.

      Parameters

      Returns Promise<any>

    • This utility method calls GetDataObject() internally and formats the result as a JSON string. If you want to get the data as an object instead of a string, call GetDataObject() directly.

      Parameters

      Returns Promise<string>

    • Retrieves all descendant records in the hierarchy under this record using a single RunView query.

      Type Parameters

      Parameters

      • Optionaloptions: number | { maxDepth?: number; parentFieldName?: string }

      Returns Promise<T[]>

      Array of descendant entity instances ordered by hierarchy depth.

    • Convenience method to access a field by code name. This method is case-insensitive and will return null if the field is not found.

      Parameters

      • codeName: string

      Returns EntityField

    • Convenience method to access a field by name. This method is case-insensitive and will return null if the field is not found. You can do the same thing with more fine tune controlled by accessing the Fields property directly.

      Parameters

      • fieldName: string

      Returns EntityField

    • Utility method to return the Name of the record (the value of the column that comes back from EntityInfo.NameField) from the current object. This avoids needing a network round trip to get the record name whenever we have the object already loaded in memory.

      Returns any

    • Resolves the recursive foreign key field for this entity. If parentFieldName is provided, finds that specific field. Otherwise defaults to 'ParentID' if present, or the first self-referencing foreign key field found on the entity.

      Parameters

      • OptionalparentFieldName: string

      Returns EntityFieldInfo

    • Resets this entity to a pristine state and populates it from the provided data object.

      Unlike SetMany, which incrementally updates existing field values, Hydrate() first resets ALL internal state — fields, composite key cache, loaded/saved flags — then populates from the provided data as if loading a fresh record from the database.

      This is critical for IS-A (table-per-type) inheritance: when a child entity loads its record, parent entities in the chain must be fully reset and re-populated from the child's view data, including the shared primary key. After init(), each EntityField's _NeverSet flag is true, allowing even ReadOnly PK fields to be set exactly once via SetMany.

      After population, entities are automatically marked as saved/loaded when all PK values are present (via UpdateSavedStateFromPrimaryKeys).

      The parent chain is handled recursively: if this entity has an IS-A parent, the parent is hydrated first (deepest ancestor first). Each level only receives the fields it owns — a child's view row is the union of every ancestor plus its own columns, and passing that whole row to the parent used to trip WarningManager ("fields were not found in entity definitions") for every child-only column. That is how loading Accounting Company Profiles as entity objects produced a MJ: Companies missing-field dump at MJAPI boot.

      Parameters

      • data: Record<string, unknown>

        A plain object whose properties map to field names on this entity (and potentially parent entities in the IS-A chain).

      Returns void

    • Discovers and initializes the IS-A child entity for a loaded record.

      After a record is loaded, this method checks whether a more-derived child entity record exists with the same primary key. If found, it creates the child entity instance, shares the current instance chain (so child._parentEntity === this), and recursively discovers further children down the hierarchy.

      This ensures that Save/Delete operations always delegate to the leaf entity, running the full validation and event chain at every level.

      Must be called AFTER a record is loaded (PK must be available). Skipped for entities that are not parent types or have already been discovered.

      Returns Promise<void>

    • Constructs every declared embedded peer without NewRecord or Load. Called from GetEntityObject after InitializeParentEntity.

      Parameters

      • Optionalvisited: Set<string>

        Entity names already being constructed (cycle guard).

      Returns Promise<void>

    • Initializes the IS-A parent entity composition chain. For child type entities, this creates the parent entity instance (and recursively its parent, etc.) and caches the parent field name set for routing.

      Must be called AFTER EntityInfo is available but BEFORE any Load/NewRecord/Set/Get. This is called by Metadata.GetEntityObject() after constructing the entity.

      Returns Promise<void>

      • This method loads a single record from the database. Make sure you first get the correct BaseEntity sub-class for your entity by calling Metadata.GetEntityObject() first. From there, you can call this method to load your records.
      • NOTE: You should not be calling this method directly from outside of a sub-class in most cases. You will use the auto-generated sub-classes that have overriden versions of this method that blow out the primary keys into individual parameters. This is much easier to program against.

      Parameters

      • CompositeKey: CompositeKey

        Wrapper that holds an array of objects that contain the field name and value for the primary key of the record you want to load. For example, if you have a table called "Customers" with a primary key of "ID", you would pass in an array with a single object like this: {FieldName: "ID", Value: 1234}. *If you had a composite primary key, you would pass in an array with multiple objects, one for each field in the primary key. You may ONLY pass in the primary key fields, no other fields are allowed.

      • OptionalEntityRelationshipsToLoad: string[]

        Optional, you can specify the names of the relationships to load up. This is an expensive operation as it loads up an array of the related entity objects for the main record, so use it sparingly.

      Returns Promise<boolean>

      true if success, false otherwise

    • Loads the MJ: Entities record from the database

      Parameters

      • ID: string
      • OptionalEntityRelationshipsToLoad: string[]

        (optional) the relationships to load

      Returns Promise<boolean>

      • true if successful, false otherwise

      MJEntityEntity

    • Loads entity data from a plain object, typically from database query results.

      This method is meant to be used only in situations where you are sure that the data you are loading is current in the database. MAKE SURE YOU ARE PASSING IN ALL FIELDS. The Dirty flags and other internal state will assume what is loading from the data parameter you pass in is equivalent to what is in the database.

      Parameters

      • data: any

        A simple object that has properties that match the field names of the entity object

      • Optional_replaceOldValues: boolean

      Returns Promise<boolean>

      Promise - Returns true if the load was successful

      Generally speaking, you should use Load() instead of this method. The main use cases where this makes sense are:

      1. On the server if you are pulling data you know is fresh from the result of another DB operation
      2. If on any tier you run a fresh RunView result that gives you data from the database
      3. When the RunView Object RunView() method is called with ResultType='entity_object'

      Important for Subclasses: As of v2.53.0, this method is now async to support subclasses that need to perform additional asynchronous loading operations (e.g., loading related data, fetching additional metadata).

      Subclasses that need to perform additional loading should override BOTH this method AND Load() to ensure consistent behavior regardless of how the entity is populated. This is because these two methods have different execution paths:

      • Load() fetches data from the network/database and then calls provider-specific loading
      • LoadFromData() is called when data is already available (e.g., from RunView results)
      // Subclass implementation
      public override async LoadFromData(data: any, replaceOldValues: boolean = false): Promise<boolean> {
      const result = await super.LoadFromData(data, replaceOldValues);
      if (result) {
      // Perform additional async loading here
      await this.LoadRelatedData();
      await this.LoadMetadata();
      }
      return result;
      }

      // Don't forget to also override Load() for consistency, unless you INTEND to have different behavior
      // for Load() vs LoadFromData()
      public override async Load(ID: string, EntityRelationshipsToLoad: string[] = null): Promise<boolean> {
      const result = await super.Load(ID, EntityRelationshipsToLoad);
      if (result) {
      // Same additional loading as in LoadFromData
      await this.LoadRelatedData();
      await this.LoadMetadata();
      }
      return result;
      }
    • Populates this record's declared related-record collections and resolves once they are all ready — the one call to await when you want a fully-hydrated record.

      The point is batching. Cache-sourced collections resolve synchronously against BaseEngineRegistry and cost nothing; every database-sourced collection is gathered into a single RunViews call rather than one RunView each. So a record with four declared collections costs one round trip, or zero when they all read from engine caches — instead of the four sequential queries a naive for (…) await c.Load() would issue.

      Collections declared 'never' are skipped: that mode means write-only staging buffer.

      Parameters

      • ...names: string[]

        Collection names to load. Omit to load every declared collection.

      Returns Promise<void>

      await action.LoadRelatedRecords();              // Params, ResultCodes and Libraries, one trip
      await agent.LoadRelatedRecords('Prompts'); // just the one
    • This method will create a new state for the object that is equivalent to a new record including default values.

      Parameters

      • OptionalnewValues: FieldValueCollection

        optional parameter to set the values of the fields to something other than the default values. The expected parameter is an object that has properties that map to field names in this entity. This is the same as creating a NewRecord and then using SetMany(), but it is a convenience/helper approach.

      Returns boolean

    • Used for raising events within the BaseEntity and can be used by sub-classes to raise events that are specific to the entity.

      Parameters

      • type:
            | "delete"
            | "save"
            | "new_record"
            | "load_complete"
            | "transaction_ready"
            | "save_started"
            | "delete_started"
            | "load_started"
            | "remote-invalidate"
            | "graph_save_started"
            | "graph_save"
            | "other"
      • payload: any
      • OptionalsaveSubType: "update" | "create"

      Returns void

    • Raises the transaction_ready event. This is used to indicate that the entity object is ready to be submitted for transaction processing. This is used by the TransactionGroup class to know when all async preprocessing is done and it can submit the transaction. This is an internal method and shouldn't be used by sub-classes or external callers in most cases. It is primarily used by Provider classes who are handling the tier-specific processing for the entity object.

      Returns void

    • Re-fetches the current record from the database using its existing primary key, replacing all in-memory field values with the latest data from the database. This is useful when you know (or suspect) the record has been modified externally (e.g., by a trigger, another user, or a background process) and you want to bring the entity object up to date.

      Returns Promise<boolean>

      true if the record was successfully reloaded, false if the provider returned no data.

      • The entity must have been previously loaded or saved (i.e., it must have a valid PrimaryKey). Calling Refresh() on a new, unsaved entity will throw because the primary key is not yet valid.
      • After a successful refresh, all field dirty flags are reset — the entity will report Dirty === false.
      • This is equivalent to calling InnerLoad(this.PrimaryKey).
      • If you only need to discard unsaved in-memory changes (without a database round-trip), use Revert instead.

      If the entity has no provider set, the primary key is invalid, or the user lacks Read permission.

    • Registers a companion on this entity. Called from a subclass constructor or field initialiser, normally via DeclareRelatedRecords.

      Type Parameters

      Parameters

      Returns TCompanion

      The same companion, so it can be assigned to a readonly field in one expression.

      When a companion with the same name is already registered — a duplicate name would make the wire payload ambiguous and silently drop one of the two.

    • This method can be used to register a callback for events that will be raised by the instance of the BaseEntity object. The callback will be called with a BaseEntityEvent object that contains the type of event and any payload that is associated with the event. Subclasses of the BaseEntity can define their own event types and payloads as needed.

      Parameters

      Returns Subscription

    • Append a result to _resultHistory, trimming the oldest entries when over MAX_RESULT_HISTORY. All Save/Delete code paths route through this — both inside BaseEntity and in callers like databaseProviderBase and entity subclasses that record their own results.

      Parameters

      Returns void

    • If the entity object has a TransactionGroup associated with it, the TransactionGroup will be notified that we are doing some transaction pre-processing so that the TransactionGroup can properly wait for those pre-processing steps to complete before submitting the transaction. This method should generally NOT be called by anyone other than a provider that is handling the tier-specific processing for the entity object.

      Returns void

    • Resets the vector embeddings for this entity to an empty state.

      Returns void

    • Prospective counterpart to FindISAChildEntity. Evaluates which IsA child subtype entity this record should have based on:

      1. Registered EntitySubtypeResolver (ClassFactory key = entity name)
      2. Entity.SubtypeSelector declarative FK traversal path
      3. Unconditional single-child IsA fallback (ChildEntities.length === 1)
      4. Otherwise null (no subtype)

      Returns Promise<string>

      plans/sync-composition-axes.md

    • This method will revert the internal state of the object back to what it was when it was last saved, or if never saved, from when it was intially loaded from the database. This is useful if you want to offer a user an "undo" type of feature in a UI.

      Returns boolean

    • Saves the current state of the object to the database. Uses the active provider to handle the actual saving of the record. If the record is new, it will be created, if it already exists, it will be updated.

      Debounces multiple calls so that if Save() is called again while a save is in progress, the second call will simply receive the same result as the first.

      For a Table-Per-Type child, this saves EVERY level — root first, then down to this entity — inside one transaction, with a single primary key shared across all of them. Set fields belonging to any ancestor directly on this object; Set routes each one to the entity that owns it. There is no depth limit.

      // Webinar IS-A Meeting IS-A Product
      const webinar = await md.GetEntityObject<WebinarEntity>('Webinars', contextUser);
      webinar.NewRecord();
      webinar.RecordingURL = '...'; // Webinar's own
      webinar.StartTime = start; // Meeting's
      webinar.Name = 'Q1'; // Product's — set on the SAME object
      await webinar.Save(); // writes Product, Meeting, Webinar

      Do NOT create the parent separately and then try to attach a child to it — NewRecord() starts a new chain rather than adopting an existing parent row, so that produces a second parent and a primary-key conflict.

      If a PARENT level fails validation, this returns false and the failure is reported on THIS entity's result as Failed to save parent entity '<Name>': <detail>. The commonest cause is a NOT NULL column on an ancestor table that was never set — the child looks complete and the save still fails. (Before v5.50.0 that result was recorded only on the parent object, so the caller saw false with a null LatestResult and an empty ResultHistory.)

      Parameters

      Returns Promise<boolean>

      Promise

      • ISAParent to inspect the parent instance directly
      • packages/MJCore/docs/isa-relationships.md — "Creating a Child Record"
    • Serializes every registered companion that has something to send.

      Companions returning null are omitted entirely, so a header-only save on a composite entity ships no companion payload at all and costs nothing extra on the wire.

      Parameters

      • Optionalmode: EntityCompanionDeserializeMode

        'request' omits clean saved companions. 'result' ships authoritative post-save state so the other tier can mark peers saved.

      Returns Promise<EntityCompanionPayload[]>

      The companion payloads, in declaration order.

    • Seeds the embed-load cycle set for a nested InnerLoad. Called by EmbeddedRecord.LoadEager so inherit walks share one entityName:PK path and a self-parented row fails cleanly instead of recursing forever.

      Parameters

      • visited: Set<string>

      Returns void

    • NOTE: Do not call this method directly. Use the From method instead

      Sets any number of values on the entity object from the object passed in. The properties of the object being passed in must either match the field name (in most cases) or the CodeName (which is only different from field name if field name has spaces in it)

      For IS-A child entities, all fields are first set on self (including parent fields as mirrors), then parent fields are extracted and forwarded to _parentEntity.SetMany() for authoritative state, including proper OldValue tracking via the replaceOldValues parameter.

      Parameters

      • object: any
      • OptionalignoreNonExistentFields: boolean

        if set to true, fields that don't exist on the entity object will be ignored, if false, an error will be thrown if a field doesn't exist

      • OptionalreplaceOldValues: boolean

        if set to true, the old values of the fields will be reset to the values provided in the object parameter, if false, they will be left alone

      • OptionalignoreActiveStatusAssertions: boolean

        if set to true, the active status assertions for the fields will be ignored, if false, an error will be thrown if a field is not active. Defaults to false.

      Returns void

    • Marks the next Save() as a restore from a historical RecordChange row.

      The provider will write a new RecordChange entry with Source='Restore', RestoredFromID pointing at sourceChangeId, and RestoreReason set to reason (or NULL). This produces an auditable lineage chain that the timeline UI can render via the RestoredFromID foreign key.

      The context is consumed exactly once per Save() and persists on the entity until either (a) overwritten by a subsequent SetRestoreContext() call or (b) explicitly cleared via ClearRestoreContext(). It is NOT auto-cleared inside Save() because TransactionGroup execution is deferred — see the comment on _restoreContext for details.

      Parameters

      • sourceChangeId: string

        The ID of the historical RecordChange row whose state is being restored. Required; throws if empty.

      • Optionalreason: string

        Optional user-entered explanation captured at restore time. Persisted to RecordChange.RestoreReason for audit purposes.

      Returns void

      record.SetRestoreContext(versionId, 'Reverting incorrect Q2 entries');
      const ok = await record.Save();
      record.ClearRestoreContext();
    • Specifies if the current object supports the

      Returns boolean

      EmbedTextLocal method or not - useful to know before calling it for conditional code that has fallbacks as needed. BaseEntity does not implement this method but server-side sub-classes often do, but it is not mandatory for any sub-class.

    • Strongly-typed wrapper for the GetAll method

      Type Parameters

      • K extends AnyZodObject

      Parameters

      • Optionalschema: K

        the zod schema to validate the data against

      Returns TypeOf<K>

    • Validate() method override for MJ: Entities entity. This is an auto-generated method that invokes the generated validators for this entity for the following fields:

      • Table-Level: This rule ensures that if deleting via the API is allowed and the delete type is set to 'Soft', then record merging must also be allowed. In other words, you cannot allow API deletes with a soft delete type without also allowing record merging.
      • Table-Level: If direct SQL deletion is allowed, the delete type must be set to 'Hard' to ensure data integrity.
      • Table-Level: Direct SQL operations (Insert, Update, and Delete) must be disabled if Track Record Changes or Trust Server Cache Completely is enabled, ensuring that cache integrity and change tracking are not bypassed.
      • Table-Level: If the base view is marked as generated, the generated base view name must be null. A generated base view name can only be set when the base view is not marked as generated.
      • Table-Level: If a generated base view name is specified, a base view must also be defined, and the generated base view name cannot be the same as the base view name to prevent naming conflicts.

      Returns ValidationResult

    • Asynchronous validation method that can be overridden by subclasses to add custom async validation logic. This method is automatically called by Save() AFTER the synchronous Validate() passes.

      IMPORTANT:

      1. This should NEVER be called INSTEAD of the synchronous Validate() method
      2. This is meant to be overridden by subclasses that need to perform async validations
      3. The base implementation just returns success - no actual validation is performed
      4. Overriding this method is what turns it on. You do NOT also have to override DefaultSkipAsyncValidation — that getter is for stating a policy explicitly, and an explicit override of it (either value) still wins. To suppress async validation for one call, pass SkipAsyncValidation: true in the save options.

      Point 4 used to be the opposite, and it was not discoverable: DefaultSkipAsyncValidation defaults to true, so an override written against this docstring alone never ran. It reads as enforced, reviews as enforced, and was not — the failure mode that let an order confirm with no lines in production.

      Subclasses should override this to add complex validations that require database queries or other async operations that cannot be performed in the synchronous Validate() method.

      Returns Promise<ValidationResult>

      Promise A promise that resolves to the validation result

    • Clears the static memoization cache used by SubtypeSelector path evaluation.

      Returns void

    • Resolves the leaf (most-derived) entity type for a given parent entity record. Walks down the IS-A child hierarchy to find which child type a record belongs to. Returns the child entity name, or the parent's own name if no children exist. Useful for polymorphic operations where you have a parent record and need to know its actual leaf type.

      Parameters

      • entityName: string

        The parent entity name

      • primaryKey: CompositeKey

        The primary key to look up

      • OptionalcontextUser: UserInfo

        Optional context user for server-side operations

      • Optionalprovider: IMetadataProvider

      Returns Promise<{ IsLeaf: boolean; LeafEntityName: string }>

      The leaf entity name and whether it was resolved to a child type