Attributes

Attributes modify field behavior on both the frontend and backend.

Quick Reference

AttributeEffectEnforcementExample
UINameSets lookup display fieldUI[UIName] public string Name { get; set; }
UIDescriptionSets lookup descriptionUI[UIDescription] public string Info { get; set; }
UIDisplayNameCustom field label (field) or BaseEntity overrides (class)UI[UIDisplayName("Serial #")] public string Name
UIRequiredRequired field with validationUI + Backend[UIRequired] public string Name { get; set; }
UIRecommendedShows blue cross indicatorUI only[UIRecommended] public decimal Price { get; set; }
UIHideHidden from UIBackend[UIHide] public decimal InternalCost { get; set; }
UIReadOnlyDisplay only, no editing (field) or BaseEntity protection (class)Backend[UIReadOnly] public decimal Price { get; set; }
UICreateOnlyEditable on create only (field) or BaseEntity protection (class)Backend[UICreateOnly] public Guid OfferId { get; set; }
UIOptionDropdown from Options tableUI[UIOption("Category")] public Guid? CategoryId
UIDateFormatDate display formatUI[UIDateFormat("lll")] public DateTime OrderDate
UIMultiSelectMany-to-many via junction tableBackend[UIMultiSelect(...)] public ICollection<T> Tags
CascadeDeleteCascade delete on FKBackend[CascadeDelete] public Guid? AddressId { get; set; }

Complete Example

Widget Entity with Multiple Attributes

[Table(nameof(Widget))]
// Override BaseEntity field display names (supports multiple)
[UIDisplayName("Owner", nameof(OwningUserId))]
[UIDisplayName("Created", nameof(CreatedDate))]
[UIDisplayName("Last Modified", nameof(UpdatedDate))]
// Make BaseEntity fields read-only (single attribute, multiple fields)
[UIReadOnly(nameof(OwningUserId), nameof(CreatedDate), nameof(UpdatedDate))]
// Make BaseEntity fields create-only (single attribute, multiple fields)
[UICreateOnly(nameof(OwningUserId), nameof(OwningTeamId))]
public class Widget : BaseEntity
{
public Guid WidgetId { get; set; }
// UIName - Used in lookup dropdowns
[UIName]
public string Name { get; set; }
// UIDescription - Shown below name in lookups
[UIDescription]
public string Description { get; set; }
// UIRequired - Mandatory field (asterisk shown)
[UIRequired]
public string SerialNumber { get; set; }
// UIRecommended - Blue cross indicator
[UIRecommended]
public decimal Price { get; set; }
// UIDisplayName - Custom label
[UIDisplayName("Internal Cost")]
public decimal Cost { get; set; }
// UIHide - Hidden from UI but queryable
[UIHide(queryable: true)]
public decimal InternalMargin { get; set; }
// UIReadOnly - Can read but not edit from UI
[UIReadOnly]
public decimal CalculatedTotal { get; set; }
// UICreateOnly - Set on create, then becomes read-only
[UICreateOnly]
public string BatchNumber { get; set; }
// UIOption - Dropdown from Options table
[UIOption("WidgetType")]
public Guid? WidgetTypeId { get; set; }
public Option WidgetType { get; set; }
// UIDateFormat - Custom date format (Day.js)
[UIDateFormat("lll")]
public DateTime ManufacturedDate { get; set; }
// UIMultiSelect - Many-to-many relationship via junction table
[UIMultiSelect(nameof(WidgetTag.WidgetId), nameof(WidgetTag.TagId))]
public ICollection<WidgetTag> Tags { get; set; }
// Relationships with cascade behavior
public Guid CompanyId { get; set; } // Required - cascade delete
public Company Company { get; set; }
public Guid? ManufacturerId { get; set; } // Optional - set null on delete
public Manufacturer? Manufacturer { get; set; }
[CascadeDelete]
public Guid? WarrantyId { get; set; } // Optional but cascade delete
public Warranty? Warranty { get; set; }
}

UIName & UIDescription

When selecting a Widget in a lookup, the Name field is displayed with the Description underneath.

UIRequired

Shows asterisk (*) and validates on submit.

Shows blue cross (✚) to indicate recommended field.

UIDisplayName

Custom label instead of property name.

UIOption Setup

Options are managed from the Admin Dashboard under System → Options.

Option Entity Fields:

  • Name: Option group identifier (matches UIOption parameter, e.g. "TodoPriority")
  • Label: Display text shown in dropdown
  • Value: Optional code/value for the option
  • Order: Sort order in dropdown

Example:

[UIOption("TodoPriority")]
public Guid? PriorityId { get; set; }
public Option Priority { get; set; }

This creates a dropdown populated with all Options where Name == "TodoPriority".

UIHide

// Hidden and not queryable
[UIHide]
public decimal Secret { get; set; }
// Hidden but can be used in filters
[UIHide(queryable: true)]
public decimal InternalCost { get; set; }

UICreateOnly

Field can be set on create but becomes read-only afterward.

Field-level:

[UICreateOnly]
public Guid OfferId { get; set; }

Class-level (BaseEntity fields):

[UICreateOnly(nameof(OwningUserId), nameof(CampaignId))]
public class Coupon : BaseEntity

UIDateFormat

Uses Day.js format strings:

  • "lll" → Oct 14, 2025 9:30 PM
  • "YYYY-MM-DD" → 2025-10-14
  • "MMM D, YYYY" → Oct 14, 2025

UIMultiSelect

Creates many-to-many relationships through junction tables with automatic UI and data management.

Entity with UIMultiSelect:

[Table(nameof(EmailMessage))]
public class EmailMessage : BaseEntity
{
public Guid EmailMessageId { get; set; }
[UIDisplayName("To Recipients")]
[UIMultiSelect(nameof(EmailMessageContact.EmailMessageId), nameof(EmailMessageContact.ContactId))]
public ICollection<EmailMessageContact> To { get; set; }
}

Junction Table:

public class EmailMessageContact
{
public Guid EmailMessageContactId { get; set; }
// Owner FK (first parameter)
public Guid EmailMessageId { get; set; }
public EmailMessage EmailMessage { get; set; }
// Target FK (second parameter)
public Guid ContactId { get; set; }
public Contact Contact { get; set; }
// Optional: Additional fields (preserved but not managed by UIMultiSelect)
public DateTime? SentDate { get; set; }
}

Target Entity:

public class Contact : BaseEntity
{
public Guid ContactId { get; set; }
[UIName]
public string Name { get; set; }
[UIDescription] // Optional: shows below name in dropdown
public string Email { get; set; }
}

Frontend Usage:

<Field name="To" /> // Automatically renders MultiSelect

Data Format:

Read requests return UIMultiSelect fields as arrays of objects with id (target entity ID) and name properties:

{
"data": {
"results": [
{
"EmailMessageId": "3b7be37c-4389-4a52-88d5-b763b4809fd8",
"To": [
{
"id": "b0d50638-9d7e-493d-9d7b-b159262a9746",
"name": "John Smith"
},
{ "id": "68fbc5c5-fdeb-45d8-b435-dfc040eb383a", "name": "Sandy Jean" }
]
}
]
}
}

On create or update, adding/removing objects with id (target entity ID) and name properties will add or remove the corresponding N:N junction records.

Permissions:

  • Primary entity: CREATE (on create) or UPDATE (on update) required
  • Junction entity: CREATE and DELETE required
  • Target entity: READ required
  • Permissions can be at USER, TEAM, or SYSTEM level

Cascade Delete Rules

Cascade behavior is determined by nullable operator and [CascadeDelete] attribute:

ConfigurationBehavior
public Guid ForeignId (required)Deleting parent deletes this record
public Guid? ForeignId (optional)Deleting parent sets FK to null
[CascadeDelete] public Guid? ForeignIdDeleting parent deletes this record

Was this page helpful?