You use a tuple when an OCL expression must return a temporary result made from several values—such as an object, a grouping key, and a calculated total—without adding a new class to your model.
What is a tuple?
A tuple is one result assembled from named or generated parts. It is useful when the result shape exists only for an expression, report, grid, or calculation and is not a persistent business concept in your model.
For example, a sales summary can return one tuple per date containing:
- the date used as the grouping key; and
- the sales belonging to that date.
This is comparable to selecting explicit columns in SQL rather than selecting every column. The selected values form each returned row. In MDriven, a tuple can also contain references to real model objects alongside calculated values. You can therefore use a returned object reference to navigate further in OCL or present properties from that object.
A tuple is not a new modeled class. MDriven generates a result type for the expression, with properties for its parts.
When to use tuples
Use a tuple when you need to combine values that do not belong together on one existing class.
| Need | Tuple example |
|---|---|
| Group records by a value | A date and the collection of sales made on that date. |
| Return an object with a calculation | A customer reference and that customer's total sales. |
| Return several calculated values | A product, its quantity sold, and its sales amount. |
| Work with a database query result | The parts returned by PSEvalTuples. |
If the result needs its own lifecycle, associations, or persisted attributes, model a class instead of relying on a tuple.
How OCL creates tuples
Several OCL constructs produce tuples. The tuple's available properties depend on the expression that produced it.
| Construct | Result | Example use |
|---|---|---|
| groupBy | A grouping criterion and the matching objects in a List property.
|
Group sales by date before calculating totals per date. |
collect with multiple collected expressions
|
A collection of tuples whose parts are the collected expressions. | Split and pair related string values, such as a name and address segment. |
| product | A set of tuples with first and second parts representing a cartesian product.
|
Pair each item in one collection with each item in another collection. |
| PSEvalTuples | A list of tuples returned from an OCL expression evaluated against the database. | Return an assignment, consultant, and calculated billed-hours total. |
Grouping example
The following expression groups Class3 objects reached from all Class1 instances by Attribute1:
IElement elem = ocl.Evaluate("Class1.allinstances.class2.class3->groupby(x|x.Attribute1)");
Each result is a tuple. For this grouping expression, the tuple has:
Attribute1— the value used as the grouping criterion.List— the collection of objects whoseAttribute1has that value.
Use groupBy when you need the grouped objects and then want to calculate values from each group. For example, the values in List can be used to calculate a sum for that group.
Collecting multiple parts
A collect expression can create a tuple by returning multiple values for each input item. This example splits text into pairs:
'A, B;
X, Y'.Split(';'.toCharArray)->collect(pair |
pair.Split(','.toCharArray)->at(1),
pair.Split(','.toCharArray)->at(2))The result is a collection of tuples, each containing the two extracted string parts. See split for the string-splitting requirements and additional examples.
Access tuple parts in OCL and a ViewModel
Tuple parts are available as properties of the result. A part can be an object reference, a derived value, or a calculated value. The part names come from the expression; where OCL cannot infer a descriptive name for a calculated part, it can use generated names such as Part1.
When you present a tuple in a ViewModel, derive the column from the referring tuple column when the expected type is a modeled class but the actual result is a tuple. Then add columns for the tuple parts that you need to show.
For example, if a tuple contains a customer reference and a calculated sales value:
- add a column that refers to the customer part, then show the customer's name through that reference;
- add a column for the calculated part; and
- give the presentation columns meaningful names, such as Customer name and Sales, even if the calculated tuple part is generated as
Part1orPart2.
A tuple can mix object references and calculated values. The customer part remains a reference to the model object, so you can navigate from it to other customer information instead of treating it as detached SQL data.
If a tuple result needs more processing or must be retained in a screen model, create transient instances and copy the tuple values into them in an action. This gives the result a modeled shape for subsequent presentation or processing.
Access tuples from C# and CodeDress
In C# or CodeDress, cast a tuple result to ITuple. Iterate through its Properties collection and read each property's AsObject value.
var oneMemTuple = memoryresult[0] as ITuple;
var onePSCase1Tuple = resultFromSQL92Joins[0] as ITuple;
var onePSCase2Tuple = resultFromNormalJoins[0] as ITuple;
for (int i = 0; i < oneMemTuple.Properties.Count; i++)
{
var property = oneMemTuple.Properties[i];
var propertyPS1 = onePSCase1Tuple.Properties[i];
var propertyPS2 = onePSCase2Tuple.Properties[i];
if (property.AsObject != null)
{
Assert.IsTrue(
property.AsObject.Equals(propertyPS1.AsObject),
property.StructuralFeature.Name + " differs (sql92joins=true)");
Assert.IsTrue(
property.AsObject.Equals(propertyPS2.AsObject),
property.StructuralFeature.Name + " differs (sql92joins=false)");
}
}
In this example, StructuralFeature.Name identifies the tuple property being compared. Check for null before calling Equals, as shown.
Tuples returned from PSEvalTuples
PSEvalTuples lets you use oclPS in OCL and EAL (action language) and returns a list of tuples. It is intended for database-side evaluation, including aggregate calculations.
For example, a PSEvalTuples expression can return an assignment, its consultant, and a sum of billed hours. The returned tuple can therefore contain both model-object references and a calculated numeric part.
Aggregation limitation
Do not rely on one PSEvalTuples tuple to calculate aggregates over different filtered sets of rows. Combining calculations such as a sum for one condition and a maximum for another condition can produce results that do not match the OCL intent when translated to SQL.
For example, avoid a single tuple expression shaped like:
->collect(x|x,
x.Name,
x.Something->select(goodone).Value->sum,
x.Something->select(badone).Value->sum)Split the work into one expression per aggregation and verify results from every new database-side aggregate expression. Also ensure that the database has the indexes and configuration needed to execute the expression efficiently. See PSEvalTuples for the expression template, update dependency behavior, and further limitations.
