Skip to main content

Model Attributes

Ormed models support attribute metadata that affects:

  • Mass assignment (fill, fillIfAbsent, forceFill)
  • Serialization (toArray, toJson)
  • Casting (see Models → Casting)
Tracked models

These APIs are designed for tracked models (the generated $Model types) and instances returned by queries. Plain user-defined model instances are immutable and typically not used for mass assignment.

Define metadata

Attribute metadata can be declared at the model level, and optionally overridden per-field.

(
table: 'accounts',
fillable: ['email', 'name'],
guarded: ['is_admin'],
hidden: ['password_hash'],
visible: ['password_hash'],
appends: ['display_name'],
)
class Account extends Model<Account> {
const Account({
required this.id,
required this.email,
required this.passwordHash,
this.name,
this.isAdmin = false,
});

(isPrimaryKey: true, autoIncrement: true)
final int id;

final String email;

(columnName: 'password_hash')
final String passwordHash;

final String? name;

(columnName: 'is_admin', guarded: true)
final bool isAdmin;

Mass assignment

Mass assignment takes a Map<String, Object?> keyed by column names and applies fillable/guarded rules.

void massAssignmentExample() {
final account = $Account(id: 1, email: 'a@example.com', passwordHash: 'hash');

// Only fillable columns are applied; guarded columns are discarded.
account.fill({'email': 'new@example.com', 'is_admin': true});

// Enable strict mode to throw instead of silently discarding.
try {
account.fill({'is_admin': true}, strict: true);
} on MassAssignmentException {
// Handle mass assignment failures.
}

// Bypass guards for trusted code paths.
account.forceFill({'is_admin': true});
}

Notes:

  • fill(...) defaults to strict: false (guarded keys are discarded).
  • Set strict: true to throw a MassAssignmentException when a guarded key is present.
  • Use forceFill(...) only for trusted/internal flows.
  • fill / fillIfAbsent / forceFill accept tracked models, DTOs, and partials in addition to maps.
  • Map keys can be Dart field names or column names (they are normalized).

Serialization (hidden / visible)

toArray() / toJson() honor hidden by default. To include hidden values you must set includeHidden: true, and the column must also be listed in visible.

Map<String, Object?> serializationExample() {
final account = $Account(id: 1, email: 'a@example.com', passwordHash: 'hash');

// Hidden columns are excluded.
final safe = account.toArray();

// Hidden columns can be included, but only when they're explicitly visible.
final internal = account.toArray(includeHidden: true);

return {'safe': safe, 'internal': internal};
}

Accessors and mutators

Accessors let you transform attribute reads, while mutators normalize values when they are assigned. Define them as static members on the model, similar to query scopes.

  (attribute: 'display_name')
static String displayName(Account model, Object? _) =>
model.name ?? model.email;

(attribute: 'email')
static String normalizeEmail(Account model, String? value) =>
value?.trim().toLowerCase() ?? model.email;
Static-only accessors

Accessors and mutators must be declared as static. The generator exposes them on tracked models via extensions, so you can read tracked.displayName and call tracked.normalizeEmail('User@Example.com'). Accessors apply when using getAttribute(...) and serialization (toArray, toJson). Mutators apply when using setAttribute(...), fill(...), or tracked setters. Use getRawAttribute(...) / setRawAttribute(...) to bypass accessors/mutators.

Appends (computed attributes)

Use appends to include computed attributes in toArray() / toJson() output.

Map<String, Object?> appendsExample() {
final account = $Account(
id: 2,
email: 'User@Example.com',
passwordHash: 'hash',
name: 'User Name',
);

return account.toArray();
}