Skip to main content

Asset Value-Object Conversions

Summary

Source-backed inventory of the four value objects owned by the Asset aggregate and persisted as scalar columns on the Assets table — their domain purpose, stored columns, validation, structural equality, and query/index implications — plus the computed members that are never persisted.

Audience

Backend engineers, database reviewers, architects, QA, support, operations, security reviewers, and product owners.

Overview

The Asset aggregate models four concepts as value objects: AssetCode, AssetName, SerialNumber, and AssetAssignee. Each is configured as an EF owned type in AssetDbContext and stored inline on the same row as the aggregate — there are no separate value-object tables. Value objects use structural equality, so two instances are equal when their components match.

Confirmed persistence behavior

Value objectDomain purposeStored column(s)ConversionNullabilityValidationEqualityIndex implication
AssetCodeBusiness asset code / tagAssetCode varchar(80)Owned type in AssetDbContextRequired (navigation required)Upper-cased, trimmed, ≤80, requiredStructural, by ValueNon-unique IX_Assets_AssetCode; uniqueness is application-layer only
AssetNameDisplay nameAssetName varchar(200)Owned typeRequiredTrimmed, ≤200, requiredStructural, by ValueNot separately indexed
SerialNumberManufacturer serialSerialNumber varchar(160)Owned typeRequired at DB (empty string allowed)≤160; empty allowed for requests/consumables; IsEmpty helperStructural, by ValueNot indexed; no uniqueness
AssetAssigneeCurrent assignee referenceAssignedToUserId int?, LaborId int?Owned typeBoth nullableNone when unassigned; IsAssigned when setStructural, by both componentsNot separately indexed; owned-property filters use no dedicated index
  • Storage model: all four value objects persist inline on the Assets row via EF owned-type configuration; there are no side tables.
  • Query implications: filtering by an owned property (for example the assignee's UserId) is possible but is not backed by a dedicated index — the indexed access paths are the tenant-status, tenant-type, workflow-instance, compatibility-id, and non-unique asset-code indexes. See Indexes and Constraints.
  • Equality: value objects derive equality from their components (GetEqualityComponents), so comparisons and change detection are value-based, not reference-based.

Non-persisted computed / ignored members

These members exist in the domain but are not stored:

MemberKindNote
Asset.DomainEventsIgnored (Ignore)Not mapped
Asset.IsWorkflowManagedComputedDerived from workflow linkage
Asset.IsDeletableComputedDerived from status (Available, Requested, Rejected)
AssetAssignee.NoneComputedUnassigned sentinel
AssetAssignee.IsAssignedComputedTrue when an id is present
AssetDocumentReference.HasStoredContentComputedDerived from DocumentServiceId presence
SerialNumber.IsEmptyComputedTrue when serial is empty

Classification

Implemented owned value-object persistence with a Transitional (non-hardened) uniqueness posture.

Requires confirmation

Whether AssetCode should gain a per-tenant database unique constraint, and whether SerialNumber should carry any uniqueness, are not decided in source and require confirmation.

Diagram

See Also

Keywords

  • Asset value objects
  • Value-Object Conversions
  • Value-object conversions

Source References

  • microservices/src/asset-service/Domain/Common/ValueObjects.cs
  • microservices/src/asset-service/Infrastructure/AssetDbContext.cs
  • microservices/src/asset-service/Domain/Asset/Asset.cs
  • microservices/src/asset-service/Domain/Common/DomainPrimitives.cs

Revision Information

  • Status: Draft
  • Last reviewed: 2026-07-17
  • Review cycle: Quarterly