A derived attribute looks like it is always up to date. This is achieved
by using subscribers. Whenever you ask for the value the first time, it
will be calculated, and subscriptions placed. If any of the underlying
values change, the subscriptions will be triggered, the derived
attribute will be marked out of date, and if you ask for it again, it
will be recalculated. Subscriptions are placed automatically if you use
OCL to derive the value, and manually if you have a code-derived
attribute.
Many derived attributes are based on other attributes in the same
object, and in this case, the derived attribute would always be "in
memory" when the other attributes changed, and could be updated
together with the rest of the object. However, in many cases, the
derived attribute is based on attributes in related objects (such as an
ordersum). If one client loads one of the products of an order (but not
the order) and changes the list-price, the subscriptions of the
order-sum will not trigger (as the ordersum has not been calculated).
If the product is saved, then a persisted ordersum would simply be
wrong.
It would be possible to figure out what ordersums could be affected by
a change in a product price, but it requires reverse evaluation of
ocl-expressions (unless the derivation is performed in code, then I
think it is practically impossible).
In order to have persistent derived attributes, you would have to have
persistent subscriptions too.
There are several different approaches to achieve something similar
though. One is to have a derived attribute and a peristent attribute.
At certain events (such as shipping an order, or whenever the value of
the derived attribute is "frozen"), the persistent attribute is set to
the value of the derived attribute. After this point, the persistent
attirbute can be used instead of the derived attribute (for reporting
directly in the db, or simply improved performance).
The above can be amended with more modeled information. Assume you
have the derived attribute DerivedOrderSum and a persisted version of
the same information called PersistedOrderSum as outlined above.
To avoid having to remember when to use which one, add OrderSum,
also a derived attribute. Also add a flag indicating if the order sum
has frozen. call that boolean attribute OrderSumFrozen.
With this, use the following OCL to derive OrderSum:
if OrderSumFrozen
PersistedOrderSum
else
DerivedOrderSum
endif
That way you can refer to OrderSum in code and UI and always get the
"cheapest" calculation allowed by your business rules to retrieve your
data. OrderSumFrozen would probably be set as a consequence of the
order object changing state to Confirmed or something to that extent.