42 Cardinality Constraint Patterns
Exactly one requirements
- a person must have exactly one primary residence
- a project must have exactly one responsible officer
entity Person
{
Address primaryResidence;
}
At least one requirements
- a company must have at least one director
- a contract must have at least one signatory
entity Company
{
Person director+;
}
At most one
A person may have at most one active passport.
entity Person
{
Passport passport?;
}
Optional-but-constrained fields
Sometimes a field is optional, but if present, it must satisfy further constraints. Example: A building project may have an environmental clearance, but if it does, it must be valid.
entity Project
{
EnvironmentalClearance clearance?;
constraints
{
// ∀C:EnvironmentalClearance ∀V:Boolean
// (this.clearance(C) ∧ C.valid(V)) → V
clearance.valid;
}
}
Collections that must be non-empty when another condition holds
Example: A project with “commercial = true” must have at least one safety audit.
entity Project
{
Boolean commercial;
Audit audit*;
constraints
{
// if commercial, then there is at least 1 audit
// Shorthand for commercial → audit.Σexists;
// ∀C:Boolean (this.commercial(C) → ∃A:Audit this.audit(A))
commercial → audit:+;
}
}
Cardinality constraints on joins
A builder must hold exactly one valid licence at the time of a project.
entity BuilderLicence
{
...
Boolean valid;
}
entity Builder
{
BuilderLicence licence*;
constraints
{
// exactly one valid licence
// This is shorthand for licence.[valid].Σcount = 1
// |{ L:BuilderLicence | ∃V:Boolean this.licence(L) ∧ L.valid(V) ∧ V }| = 1
licence.[valid]:1;
}
}