Properties
Properties define the data fields on an entity. Each property requires a [Property<T>] attribute that specifies the data type and a display label.
[Property<T>("Label")]
The generic type parameter T is a data type that controls validation, formatting, and database column type. The string argument is the human-readable label.
[Property<DataTypes.Text>("Name")]
public partial string Name { get; set; }
Properties must be partial — the source generator provides the implementation with change tracking and event hooks.
Optional Parameters
| Parameter | Type | Description |
|---|---|---|
Description |
string? |
User-facing description explaining the property's purpose |
Technical |
string? |
Internal notes for developers (not shown to end users) |
[Property<DataTypes.ProperNoun>("Full name",
Technical = "Cached property from PrimaryContact.FullName so that we do a full-text search.")]
public partial string FullName { get; }
Common Data Types
| Data Type | CLR Type | Example |
|---|---|---|
DataTypes.Text |
string |
Names, short text (max 100) |
DataTypes.IdText |
string |
IDs, SKUs — uppercase, barcode-safe (max 15) |
DataTypes.MultilineText |
string |
Long descriptions, notes (unlimited) |
DataTypes.ProperNoun |
string |
People/business names — auto title-cased (max 50) |
DataTypes.Integer |
int |
Whole numbers |
DataTypes.Decimal |
decimal |
Numbers with 2 decimal places |
DataTypes.Currency |
decimal |
Money values (2 decimals) |
DataTypes.Boolean |
bool |
True/false flags |
DataTypes.DateOnly |
DateOnly? |
Dates without time |
DataTypes.DateTime |
DateTime? |
Date and time |
DataTypes.Enum |
TEnum |
Any C# enum |
See Data Types for the complete list.
[Required]
Marks a property as non-nullable. The value must be provided before saving.
[Required]
[Property<DataTypes.IdText>("SKU")]
public partial string Sku { get; set; }
[MaxLength(n)]
Overrides the data type's default maximum length. Only applies to string properties.
[MaxLength(20)]
[Property<DataTypes.IdText>("SKU")]
public partial string Sku { get; set; }
If omitted, the data type's default max length is used (e.g., IdText defaults to 15, Text defaults to 100).
[DefaultValue(...)]
Sets the initial value when a new entity is created. Uses System.ComponentModel.DefaultValueAttribute.
using System.ComponentModel;
[Property<DataTypes.Text>("Color")]
[DefaultValue("#ffffff")]
public partial string Color { get; set; }
[Property<DataTypes.Enum>("Status")]
[DefaultValue(SalesOrderStatus.Open)]
public partial SalesOrderStatus Status { get; set; }
[DefaultValue(1)]
[Property<DataTypes.PositiveDecimal>("Factor")]
public partial decimal Factor { get; set; }
Read-Only Properties
Use ReadOnly for server-set properties:
[Property<DataTypes.Text>("Calculated status")]
[ApiAccess(PropertyAccess.ReadOnly)]
public partial string? CalculatedStatus { get; set; }
Clients can read the value. Writes return 403, including nested writes and generated reference GUID fields.
Server code can still set it.
Use PropertyAccess.Hide to block reads too. See API access for the full rules and metadata.
Use { get; } (no setter) for computed properties whose value is set by business logic:
[Property<DataTypes.ProperNoun>("Full name")]
public partial string FullName { get; }
[Virtual]
[Property<DataTypes.Currency>("Total Price")]
public partial decimal TotalPrice { get; }
Read-only properties are typically populated by Compute events in business logic.
[Virtual] on Properties
Marks a property as computed — it is not persisted to the database. The value is calculated at runtime by business logic.
[Virtual]
[Property<DataTypes.Currency>("Subtotal")]
public partial decimal Subtotal { get; }
[Virtual]
[Property<DataTypes.Currency>("Total")]
public partial decimal Total { get; }
Virtual properties:
- Have no database column
- Are recalculated when their dependencies change
- Are typically read-only (
{ get; }) - Can also be read-write (
{ get; set; }) for user-editable computed values
// Virtual but editable — user can override the computed value
[Virtual]
[Property<DataTypes.Decimal>("Quantity")]
public partial decimal QuantityUom { get; set; }
Custom Data Types on Properties
You can use domain-specific data types defined in your project (see Creating Data Types):
[Property<ProductUnitPrice>("Cost",
Description = "The cost of the product")]
public partial decimal Cost { get; set; }
[Property<ProductQuantity>("Quantity (Each)")]
public partial decimal Quantity { get; set; }
Complete Example
using System.ComponentModel;
namespace Benevia.ERP.Model.Products;
[ApiEntity]
[NaturalKey(nameof(Sku))]
public partial class Product
{
[Required]
[MaxLength(20)]
[Searchable(1, Dictionary = "simple")]
[Property<DataTypes.IdText>("SKU",
Description = "Your part number for this product")]
public partial string Sku { get; set; }
[Searchable(2)]
[Property<DataTypes.MultilineText>("Description",
Description = "The description of the product that is used in sales documents.")]
public partial string SalesDescription { get; set; }
[Property<DataTypes.Decimal>("Unit weight")]
public partial decimal UnitWeight { get; set; }
[Property<ProductUnitPrice>("Cost",
Description = "The cost of the product. This is often used to calculate the price")]
public partial decimal Cost { get; set; }
[Property<DataTypes.Website>("Website")]
public partial string Website { get; set; }
[Property<DataTypes.Text>("Color")]
[DefaultValue("#ffffff")]
public partial string Color { get; set; }
// Virtual — computed, not in database
[Virtual]
[Property<DataTypes.Boolean>("Require all units to be sold in integer quantities")]
public partial bool RequireIntegerQuantitiesForAllUOMs { get; set; }
}