🚀 Welcome to MDriven Learn –  MDriven is now on Discord!  Don’t miss the latest Release Notes.
Derived settable attributes
This page was created by Lars.olofsson on 2017-11-26. Last edited by Wikiadmin on 2026-07-29.

You can create a derived settable attribute when you want users to edit a convenient display value while MDriven stores and updates one or more underlying attributes; this is for modelers building input fields in MDriven Designer.

A derived settable attribute has two expressions:

  • An OCL derivation expression that returns the value to display.
  • An EAL OclSet expression that handles a value entered by the user and writes it back to the source attributes.

For example, you can show a time as 09:30 in a String attribute while storing it as a DateTime value. When the user changes the text to 10, the OclSet expression can convert that input to 10:00 and update the stored time.

When to use a derived settable attribute

Use a derived settable attribute when the value that is convenient to enter is not the same as the value you persist. It lets you keep conversion and update rules in the model instead of duplicating them in each UI.

Typical uses include:

  • Formatting a persisted value for entry, such as a DateTime shown as a time String.
  • Accepting more than one input format, such as decimal values written with either , or ..
  • Editing a calculated companion value and updating the persisted values from it.
  • Splitting a composite user value into separate stored values. This pattern is also called reverse derivation.

A normal derived attribute is read-only: its OCL expression calculates a value. A derived settable attribute adds an OclSet expression, so writing to the derived attribute updates its source values.

How it works

The OCL expression defines the read direction:

source attributes → displayed derived value

The OclSet expression defines the write direction:

entered value (vInputParameter) → source attributes

vInputParameter is the value supplied when the derived attribute is set. In a String-based input attribute, it is the text entered by the user.

The OclSet expression must assign the result to the persisted attributes that are the source of the derivation. Do not attempt to assign the derived attribute to itself.

Configure the attribute

  1. Create an attribute with the type required by the UI. For a formatted time field, create a nullable String attribute such as FromTimeText: String?.
  2. In the attribute's Property Inspector, set AttributeMode to the mode for a derived settable attribute.
  3. Enter the expression used to display the value in the OCL or derivation expression setting.
  4. Enter the expression used when a value is assigned in OclSet. The entered value is available as vInputParameter.
  5. Keep the actual stored values as separate attributes. In the example below, FromTime and Hours are the stored source attributes; the text attributes are input and display helpers.
  6. Test each permitted input path. If users can edit three related fields, verify that editing each one updates the other two fields as intended.

For the broader behavior and invalidation of derived values, see Training:Derived attributes & associations. For overriding derivations in subclasses, see Documentation:Derivation expressions.

Example: enter a time and duration in different ways

Consider an object that stores:

Attribute Type Purpose
FromTime DateTime Persisted start time.
Hours Decimal Persisted duration in hours.
Date Derived DateTime Easy access to a date held by a neighboring class.
EffectiveToTime Derived DateTime A companion value to FromTime, used for symmetric access to the time information.

Expose these derived settable String attributes for input:

Attribute What the user can enter What is updated
FromTimeText A start time, such as 09:30 or 9 FromTime
HoursText A duration, such as 1,50 or 1.50 Hours
ToTimeText An end time, such as 11:00 Hours when a start time exists; otherwise FromTime

With FromTime = 09:30 and Hours = 1.50:

  • FromTimeText displays 09:30.
  • HoursText displays 1,50.
  • ToTimeText displays 11:00.

If the user edits ToTimeText to 12:00, the OclSet expression recalculates Hours as 2.50. If no start time exists, entering an end time instead calculates FromTime from the existing duration.

Support function: convert entered text to a time

Add a helper function named StringToTime() to convert the entered String. It accepts a short hour-only value such as 9 by adding minutes, and it uses a fixed date so that the current date is not carried into a value that represents a time of day.

if aText.length <= 2 then
  DateTime.Parse('1900-01-01 ' + aText + ':00')
else
  DateTime.Parse('1900-01-01 ' + aText)
endif

For example, StringToTime('9') produces a value representing 09:00, and StringToTime('09:30') produces a value representing 09:30. The date 1900-01-01 is a deliberate fixed-date workaround; it prevents the current date from becoming part of the entered time.

FromTimeText

Define FromTimeText as String?.

OCL

if self.FromTime.notNull then
  self.FromTime.formatDateTime('HH:mm')
else
  String.nullValue
endif

This expression displays FromTime in 24-hour HH:mm format. If FromTime is null, it returns a null String instead of formatting a missing value.

EAL (OclSet)

self.FromTime := self.StringToTime(vInputParameter)

This expression converts the entered text and stores the result in FromTime.

HoursText

Define HoursText as String?.

OCL

self.Hours.ToString('N2').Replace('.', ',')

This displays the duration with two decimal places and replaces a dot with a comma. For example, a value of 1.5 is displayed as 1,50.

EAL (OclSet)

self.Hours := Decimal.Parse(vInputParameter.Replace(',', '.')).Round(2)

This accepts either decimal separator. For example, both 1,5 and 1.5 are parsed and stored rounded to two decimal places.

ToTimeText

Define ToTimeText as String?. This value is calculated from the start time and duration, but it can also be entered to update the underlying values.

OCL

if self.FromTime.notNull then
  self.FromTime.AddHours(self.Hours.Value.ToDouble).formatDateTime('HH:mm')
else
  String.nullValue
endif

When FromTime exists, this adds Hours and displays the resulting end time. For example, 09:30 plus 1.50 hours displays as 11:00.

EAL (OclSet)

if self.FromTime.notNull then
  self.Hours := Decimal.Create(self.StringToTime(vInputParameter).Subtract(self.FromTime).TotalHours)
else
  self.FromTime := self.StringToTime(vInputParameter).AddHours(-self.Hours.ToDouble);
  0
endif

If FromTime exists, entering an end time recalculates Hours. If it does not exist, the expression works backwards from the entered end time and the existing duration to calculate FromTime. The final 0 completes that branch of the expression.

Design and testing checklist

  • Keep one clear source of truth. In this example, persist FromTime and Hours; derive the text fields from them.
  • Make the OCL and OclSet expressions agree. If OCL formats hours to two decimals, OclSet should store the value at the same precision.
  • Handle missing source values explicitly. The time expressions return String.nullValue when no start time is available.
  • Decide which input formats you support, then test each format. This example accepts both comma and dot decimal separators and accepts an hour-only time value.
  • Test all edit paths. Enter a start time, duration, and end time independently, then confirm that the resulting persisted values and displayed companion fields are correct.
  • Treat parsing failures as an input case that needs an explicit model or UI decision. The expressions shown use DateTime.Parse and Decimal.Parse, so entered text must be parseable by those calls.

Related patterns

Use Documentation:Derived settable associations when the value being read and written is an association end rather than an attribute. See Documentation:Attribute for the distinction between persisted, transient, derived, and derived settable attributes. If your goal is to change a stored attribute's data type, use the approach described in Documentation:Attribute or Data Type Conversion rather than treating a derived helper attribute as a permanent conversion.

See also