Repository navigation
Entity Mutations
A mutation changes an Entity in response to a typed event. Register mutation events deliberately: they are the Entity's domain operations and the normal way to enforce invariants around stored fields.
sequenceDiagram
participant Caller
participant Entity
participant Fields as Fields and computations
participant Views as Dependent projections
Caller->>Entity: Send mutation event
Entity->>Entity: Run matching mutation
Entity->>Fields: Detect changed fields and recompute
Fields->>Views: Refresh dependent projections
Entity-->>Caller: Consumed / Failed
In an attribute-based interface template, mark a default interface method with [Mutation]. It must accept exactly one event argument, return void, and provide a default implementation:
using System;
using Stateflows.Entities.Attributes;
public sealed record SetQuantity(int Quantity);
public interface ICart
{
[Field]
int Quantity { get; set; }
[Mutation]
void ChangeQuantity(SetQuantity mutation)
{
if (mutation.Quantity < 0)
{
throw new ArgumentOutOfRangeException(nameof(mutation.Quantity));
}
Quantity = mutation.Quantity;
}
}The event type identifies the mutation handler. Register at most one mutation for a given event type in an Entity definition. A method marked [Mutation] is invoked by the Entity engine, not by calling it directly on the template proxy.
An equivalent builder-based registration is:
builder.AddMutation<SetQuantity>(context =>
{
if (context.MutationEvent.Quantity < 0)
{
throw new ArgumentOutOfRangeException(nameof(context.MutationEvent.Quantity));
}
context.Entity.Quantity = context.MutationEvent.Quantity;
});Send the event through the Entity behavior handle:
var result = await cart.SendAsync(new SetQuantity(3));
if (result.Status != EventStatus.Consumed)
{
// Handle rejection, failure, or an undelivered mutation.
}For a boolean result, TryMutateAsync<TEvent> returns true only when the event was consumed:
var consumed = await cart.TryMutateAsync(new SetQuantity(3));Mutation events are exact typed event registrations. If no handler matches, it is not consumed as a mutation; use the full SendResult when the distinction between event statuses matters.
The Entity runtime snapshots field values around a mutation. If stored fields changed, it recalculates dependent computed fields and refreshes projections that depend on the changed values. See Fields and Projections.
If mutation logic or a dependent computation/projection fails, the event returns EventStatus.Failed and the Entity operation is rolled back; a partially applied field update is not committed. Register an Entity exception handler to observe failures without treating them as successful mutations. Acknowledging an exception in a handler does not suppress the failure or commit partial state.
TrySetAsync is a separate, permission-controlled direct field operation. It recalculates dependent values, but bypasses mutation handlers and their domain rules. Use mutations for business commands and direct field writes only when the exposed field contract intentionally allows an external caller to set that value. See Direct field access.
Home page Support Code licensed under an MIT-style License. Documentation licensed under CC BY 4.0. © by Mikołaj Milewski, 2026
Overview
Installation
Runtimes
Orleans runtime
Concepts
Events and Structural Events
Messaging Patterns
Validation
Scheduling
Observability
Behaviors
Behavior Values
Dependency Injection
Behavioral Groups
State Machines
Concepts
State Identity
In-State Event Deferrals
Evaluation of Transitions
Exception Handling
Building blocks
Regions
States
State
Composite State
Orthogonal State
Final State
Pseudostates
Choice
Junction
Fork
Join
History
Transitions
Transition
Default Transition
Internal Transition
Activities
Concepts
Exception Handling
Implicit Fork and Join
Tokens
Building blocks
Nodes
Action Node
Decision Node
Merge Node
Initial Node
Final Node
Input Node
Output Node
Fork Node
Join Node
Accept Event Action Node
Send Event Action Node
Publish Event Action Node
Time Event Action Node
Data Store Node
Structured Activity Node
Iterative Activity Node
Parallel Activity Node
Flows
Data Flow
Control Flow
Actions
Entities
Fields
Mutations
Projections
Extensions
ClearScript
FluentValidation
JSON definitions
Minimal APIs
OneOf
OpenTelemetry
PlantUML
Scheduling