Skip to content

Unique property constraint

Adorn a property with [Unique] to enforce that the value of that property is unique across every event of this type in the event store.

Chronicle discovers [Unique]-adorned properties automatically and registers the constraints with the Kernel when the client starts.

[EventType]
public record ProjectCreated([Unique] string Name, string Description);

When multiple event types share the same constraint name, Chronicle groups them into a single constraint. A value introduced by any of the participating events is checked against all others:

[EventType]
public record UserRegistered([Unique(name: "UniqueEmail")] string Email, string DisplayName);
[EventType]
public record UserEmailChanged([Unique(name: "UniqueEmail")] string NewEmail);

Both events now participate in the same UniqueEmail constraint, so neither UserRegistered nor UserEmailChanged can introduce an email address that already exists.

The message parameter is optional. Chronicle produces a default violation message when one is not supplied:

[EventType]
public record ProjectCreated([Unique(message: "A project with this name already exists.")] string Name, string Description);

Apply [RemoveConstraint] to the event type that signals a domain object has been removed. When this event is appended, Chronicle releases the named constraint and its previously held values can be claimed again:

[EventType]
[RemoveConstraint("UniqueEmail")]
public record UserRemoved(UserId UserId);

The constraint name must exactly match the name used in the [Unique] attribute that established it.

An event type can release more than one constraint by stacking multiple attributes:

[EventType]
[RemoveConstraint("UniqueEmail")]
[RemoveConstraint("UniqueUsername")]
public record UserRemoved(UserId UserId);

The Chronicle Kernel reads the [Unique] and [RemoveConstraint] attributes when the client connects and creates the indexes it needs. Every subsequent append is checked against those indexes server-side, so no constraint logic runs in client code.