You can query data through derived attributes and associations without repeating their OCL definitions by expanding derivations before a persistent-store fetch; this page is for developers who build OCL, PSQuery, EcoQuery PS, or SearchLogic searches.
Why derivations need expansion
A derivation is an attribute or association end whose value is calculated from other model values. You define it once in the model, usually with OCL, and use its name elsewhere in the model.
For example, an apartment can expose frequently used subsets of its occupants and pets:
Apartment.TheDogs = self.Occupants.Pets->select(p | p.PetType.Breed = 'Dog')
Apartment.Grownups = self.Occupants->select(x | x.Age >= 18)
Apartment.AreThereDogs = self.TheDogs->size > 0
At runtime, a derived value is calculated from the values it depends on and is re-evaluated when needed after a relevant change. This makes derivations useful for keeping shared business definitions in one place.
A persistent store does not contain a stored column or link for a model-level derivation. Therefore, when an OCL or LINQ expression is translated to SQL for a database search, a reference such as TheDogs must be replaced with its underlying persistent navigation and selection expression. This replacement is called derivation expansion.
Expand a derivation in an OCL expression
Use IOclService.ExpandDerivationsInExpression when you need the expanded expression yourself.
- Obtain
IOclServicefrom the currentEcoSpace. - Pass the OCL expression that refers to one or more derived members.
- Use the returned expression for the persistent query scenario that requires the derived members to be expressed through persistent members.
var ocl = EcoServiceHelper.GetEcoService<IOclService>(EcoSpace);
var exp1 = ocl.ExpandDerivationsInExpression(
"Apartment.allinstances.TheDogs->select(x | x.Name = 'Benji')",
null, false, null);
var exp2 = ocl.ExpandDerivationsInExpression(
"Apartment.allinstances.Grownups->intersection(Apartment.allinstances.TheDogs.Owner)",
null, false, null);
In the first example, TheDogs is expanded before the name filter is applied:
Apartment.allinstances.Occupants.Pets
->select(p | p.PetType.Breed = 'Dog')
->select(x | x.Name = 'Benji')
In the second example, both derived associations are expanded:
Apartment.allinstances.Occupants
->select(x | x.Age >= 18)
->intersection(
Apartment.allinstances.Occupants.Pets
->select(p | p.PetType.Breed = 'Dog').Owner)
The expanded expressions no longer refer to TheDogs or Grownups. They navigate persistent members such as Occupants, Pets, PetType, and Age, so they can be used when the expression is translated for a persistent-store fetch.
Where expansion is applied automatically
You do not need to manually expand derivations for these persistent-store search paths:
| Search path | Derivation handling |
|---|---|
IOclPsService
|
Automatically expands derivations for PS fetch. |
| PSQuery | Automatically expands derivations for PS fetch. |
| EcoQuery PS | Automatically expands derivations for PS fetch. |
| The SearchLogic used by Wecpof | Automatically expands derivations for PS fetch. |
Use IOclService.ExpandDerivationsInExpression when your code needs the rewritten OCL expression explicitly. For the automatic paths, write the query in terms of the derived member that expresses the business concept, rather than duplicating its implementation.
Model for reuse, query through persistent members
Keep a definition such as TheDogs in the model when it represents a meaningful business concept used in more than one place. Other derivations can then build on it; for example, AreThereDogs uses TheDogs rather than repeating the breed filter.
When a database fetch must evaluate that definition, expansion preserves the single model definition while producing the persistent-member expression required by the query translator. This avoids maintaining one expression for runtime use and a second, copied expression for searches.
Design and troubleshooting notes
- Define the derivation with the correct result type. For example,
Grownupsis a collection of occupants, so its expression starts withself.Occupants. - Do not assume that a derived association has a corresponding stored database relation. Its definition determines how it is expanded.
- Keep the derivation expression small and focused. Compose named derivations, such as
AreThereDogsusingTheDogs, when that improves readability. - If a query result is unexpected, inspect the expanded expression. Check that each navigation and filter refers to the intended persistent member and that the final expression has the expected collection or scalar type.
- Derivation expansion concerns reading and searching. For a value that must be decomposed when it is updated, see Documentation:Reverse Derivation.
Create and maintain derivations
To create a derived attribute or association in MDriven Designer, set its mode to Derived and provide its derivation expression. Derived attributes and associations, their update behavior, and code-based alternatives are covered in Training:Derived attributes & associations. For derivation inheritance and overrides, see Documentation:Derivation expressions.
The OCL operators used in the examples, including select, intersection, and size, are described in Documentation:Part 2 OCL: Operators.
