Relatude Help

Validation happens on write

The engine checks LegalValues, LegalCharacters, RegularExpression, MinValue/MaxValue, MinLength/MaxLength, UniqueValues and MinNoInstances/MaxNoInstances every time a node is written. A write that breaks a rule fails, and its whole transaction is rolled back. Stored values are not checked again. If you tighten a rule, the database still opens, but a node that breaks the new rule cannot be saved until its value is fixed.

A refused value throws a ValueConstraintException. Its PropertyId names the property, and its message is written for the person who typed the value, for example PostCode "12" is not valid: Enter four digits.

  • Trim and CaseTransform change the value first: white space is removed from both ends, then the case is changed (invariant culture). The rules check the changed value, and the changed value is stored. So with CaseTransform = ToLowerCase, a unique email is unique however it is typed. Queries are not transformed: a query for "Ole@Example.com" on a lower-cased property finds nothing.
  • RegularExpression must match every value written, the empty value too. A pattern like ^[a-z0-9-]+$ therefore makes the value required. For an optional value, allow empty in the pattern: ^([a-z0-9-]+)?$. Without ^ and $, the pattern may match anywhere in the value. Set RegularExpressionMessage to say what a valid value looks like; without it, the message shows the pattern.
  • LegalCharacters lists the characters a value may contain. The empty value is always allowed.
  • UniqueValues on a string ignores case unless you set CaseSensitive = true. By default, no node can have "OLE" when another has "Ole". Only the check ignores case: the value is stored, sorted and queried as written.
  • LegalValues on a string is compared ordinally. The empty value is always allowed, so add MinLength = 1 to require a value.
  • LegalValues on an integer limits a plain int to the listed values. An enum property is not limited to its members: a [Flags] combination, or a member a newer version of your code adds, is accepted.
  • MinNoInstances / MaxNoInstances on [Node] count the nodes of the type and of every type that inherits from it, including nodes that are unpublished, hidden or marked as deleted. The check is on what the whole transaction leaves, so deleting a node and inserting its replacement passes at the limit. A transaction that adds nodes is refused above the maximum, and one that removes nodes below the minimum, with a NodeTypeConstraintException. So with MinNoInstances = 1 you can always insert the first node, but never delete the last.