EAV Metadata Manipulation

When interacting with fields defined as type Metadata in the Schema, you are interacting with an Entity-Attribute-Value (EAV) storage model.

In C#, these dynamic attributes are not direct properties on the entity. Instead, they are housed in an internal collection named MetadataEntries. The system provides a strongly-typed proxy property named after your field, which filters the entries for that specific metadata dictionary.

The underlying class is always generated as {EntityName}_Metadata. The values are strongly typed into physical database columns: StringValue, NumberValue, BoolValue, and DateValue.

Safely Reading a Metadata Attribute

To read a dynamic property, you must search the collection for the AttributeName.

// Example: Entity is 'Product', Metadata Field is 'CustomSpecs'
var voltageEntry = Entity.CustomSpecs.FirstOrDefault(m => m.AttributeName == "Voltage");

if (voltageEntry != null && voltageEntry.NumberValue > 240m) 
{
    AddError("CustomSpecs", "Voltage cannot exceed 240V.");
}

Writing to a Metadata Attribute

To modify or add new keys via a script, you must check if the entry exists. If it does not, you instantiate a new EAV object and add it to the MetadataEntries base collection.

// Example: Entity is 'Product', Metadata Field is 'CustomSpecs'
var reviewEntry = Entity.CustomSpecs.FirstOrDefault(m => m.AttributeName == "ReviewedBy");

if (reviewEntry == null) 
{
    // The type is always named {EntityName}_Metadata
    reviewEntry = new Struktural.Generated.Product_Metadata 
    { 
        FieldName = "CustomSpecs", // Must match the property name exactly
        AttributeName = "ReviewedBy" 
    };
    
    // Add to the base collection to ensure EF Core tracks the insertion
    Entity.MetadataEntries.Add(reviewEntry);
}

// Assign to the appropriate typed property
reviewEntry.StringValue = User.Identity?.Name ?? "System";