🚀 Welcome to MDriven Learn –  MDriven is now on Discord!  Don’t miss the latest Release Notes.
Bootcamp:Chapter 7
This page was created by Hans.karlsen on 2022-10-09. Last edited by Wikiadmin on 2026-07-29.

You can calculate a purchase date from ownership history and edit sale dates directly in a Turnkey grid; this chapter is for Bootcamp learners building the Person and Car application.

This chapter introduces derived attributes—attributes calculated from other model data rather than stored—and the settings required to edit cells in a ViewModel grid in Turnkey.

Continue from Chapter 6. When you finish, continue with Chapter 8.

What you will build

You will improve the ownership-history model and Person ViewModel so that:

  • The association end is renamed from CarsIUsedToOwn to the clearer CarsPersonUsedToOwn.
  • Each HistoricOwnership has a derived DatePurchased value.
  • A user can edit DateSold in the HistoricOwnershipGrid.
  • The calculated purchase date updates when the relevant sale date becomes available.
  • A Person can select a current car through a single-link selector.

Rename the ownership association safely

The name CarsIUsedToOwn is ambiguous because “I” does not identify the person at the other end of the association. Rename it to CarsPersonUsedToOwn.

  1. Select the association end currently named CarsIUsedToOwn.
  2. Do not rename it by typing directly in the association-end name field. A direct change causes references to the old name to fail validation.
  3. Right-click the association end and choose Rename.
  4. Enter CarsPersonUsedToOwn as the new name.
  5. Select Set former name. Use this option whenever you use Rename so MDriven can retain information needed when a later database change script is created.
  6. Click Toggle Selected to apply the rename.
  7. Save the model. Saving runs error checking; verify that the model is error-free.

Document the ownership rule

Add a note to the diagram so the calculation has an explicit business rule.

  1. Right-click the diagram and choose Add note.
  2. Double-click the note and enter:
We will assume that a person always has 1 car at a time and that when they sell the first car, that person immediately gets a new car on the same day.
  1. Close the note, resize it, and place it near the ownership model.

For example, if a person sells one car on 2024-06-01, the next ownership record can derive its purchase date as 2024-06-01.

Add a derived DatePurchased attribute

A derived attribute is calculated from an expression. Unlike a persistent attribute, it is not saved as a separate database value.

  1. Add an attribute named DatePurchased to class HistoricOwnership.
  2. Set its type to DateTime?.
  3. Select DatePurchased and use the Property Inspector to change AttributeMode from Persistent to Derived.
  4. In the Property Inspector, find DerivationOcl and click the button with three dots to open the OCL editor.

Build the derivation expression

The calculation needs the person’s ownership records in DateSold order. The expression first creates an alias named listinorder with let. It then finds the current HistoricOwnership in that ordered list and retrieves the following ownership record’s DateSold value.

Enter this expression:

let listinorder=self.Person.HistoricOwnership->orderby(h|h.DateSold) in
(
  listinorder->at0(listinorder->indexof0(self)+1)
).DateSold

The let construct creates a reference (an alias) to the ordered collection; it does not define a stored variable. The expression inside the parentheses returns a HistoricOwnership object. Appending .DateSold returns the DateTime? value required by DatePurchased.

Handle the end-of-list case

The expression must also handle an ownership record for which no following record exists. In that case, indexof0(self)+1 cannot identify a valid item, and the derived value must remain null rather than attempting an invalid lookup.

  1. Test the derivation with multiple ownership rows after completing the grid steps below.
  2. Return to DerivationOcl and update the expression with a boundary check for the missing following item.
  3. Save and test again. Verify that the record with no following ownership record shows an empty purchase date and that other rows show the expected date.

Show DatePurchased in the Person ViewModel

A ViewModel defines the data and controls that Turnkey presents to the user.

  1. Open the Person ViewModel.
  2. Locate HistoricOwnershipGrid.
  3. Add DatePurchased to the grid as a ViewModel column.
  4. Save the model and test the web application.

Initially, the derived value may be empty because there is no way to enter DateSold in the grid. The next steps enable that editing.

Make DateSold editable in the grid

A grid cell can be edited only when both conditions are true:

  • The grid is configured as editable.
  • The relevant column does not have a ReadOnly expression that evaluates to true.

Enable editing on the grid

  1. In the ViewModel editor, select the blue HistoricOwnership nesting header.
  2. Click the Tagged values button.
  3. In the tagged-values window, click Refresh from Wiki. This loads the predefined tagged-value choices, also called the value store.
  4. Find the Editable tagged value.
  5. Add Editable, set its value to True, close the window, and save.

Tagged values are additional metadata that you can apply to model elements such as classes, attributes, and ViewModels. You may define values beyond the predefined list, but predefined values have defined meaning for Turnkey and the WECPOF of the WPF engine.

Allow edits in the DateSold column

  1. Select the DateSold ViewModel column in HistoricOwnershipGrid.
  2. Clear its ReadOnlyExpression. An empty expression allows editing; an expression that evaluates to true prevents it.
  3. Save and test the web application.

The DateSold cells now render as editable date pickers. Add ownership rows if needed, then enter different sale dates. Verify that DatePurchased recalculates as the required DateSold becomes available in the related row.

  1. Click the DateSold column heading to sort the grid and check that the calculated dates match the intended ownership order.

Format DatePurchased as an ISO date

The derived model attribute remains a DateTime?. Format the value at the ViewModel column level when you need a predictable browser-independent display.

  1. Select the DatePurchased ViewModel column.
  2. Set its expression to:
self.DatePurchased.ToString('yyyy-MM-dd')
  1. Save and test the web application.

For example, a date displayed according to a browser locale can vary, while this expression displays it as 2024-06-01.

Clean up editable-grid columns

When you make the grid editable, editable columns can render as edit boxes. The Name column is an example: it does not need to be edited in this ownership grid.

  1. Select the Name ViewModel column.
  2. Set IsStatic to true.
  3. Save and verify that the value renders as plain text rather than an edit box.
  4. Remove the Name column from the grid. It always represents the same person in this context.
  5. Remove any other helper or unused columns so the grid contains only useful ownership data.

Add a current-car selector

Model the car a person currently owns, then expose that link in the Person ViewModel.

  1. On the class diagram, drag an association from class Car to class Person.
  2. Name the Car-end CurrentCar.
  3. Name the Person-end CurrentOwner.
  4. Open the Person ViewModel.
  5. Right-click in the green ViewModel tree and choose Add a Nesting ViewModelClass.
  6. Set the nesting type to SingleLinkWithSetter.
  7. Select CurrentCar as the link.
  8. Save and test the web application.

The resulting selector lets the user choose the person’s current car through the CurrentCar association.

Verify your result

Before continuing, verify all of the following:

  • The association end has been renamed to CarsPersonUsedToOwn with a former name recorded.
  • HistoricOwnership.DatePurchased is a derived DateTime? attribute.
  • HistoricOwnershipGrid is editable.
  • DateSold can be edited through a date picker.
  • DatePurchased displays in yyyy-MM-dd format when a related sale date exists.
  • The derivation handles the ownership record that has no following item.
  • The Person ViewModel includes a selector for CurrentCar.

See also