🚀 Welcome to MDriven Learn –  MDriven is now on Discord!  Don’t miss the latest Release Notes.
Custom types and custom operations in OCL
This page was created by Alexandra on 2018-10-22. Last edited by Wikiadmin on 2026-07-29.

You can use a native .NET type as an attribute type and call its exposed methods from OCL and EAL; this page is for developers who need a custom type to compare correctly in OCL.

Use a native custom type for an attribute

A custom type is a native .NET type that you define and assign as the type of a model attribute. MDriven can use such a type as an attribute type and can expose methods on that type to OCL and EAL.

For example, the following TestStruct holds two integer values and implements IComparable:

public struct TestStruct : IComparable
{
  public int Int1 { get; private set; }
  public int Int2 { get; private set; }

  public TestStruct(int int1, int int2) : this()
  {
    Int1 = int1;
    Int2 = int2;
  }

  public int CompareToX(object obj)
  {
    return CompareTo(obj);
  }

  public int CompareToX(TestStruct other)
  {
    return CompareTo(other);
  }

  public int CompareTo(TestStruct other)
  {
    return (Int1 + Int2).CompareTo(other.Int1 + other.Int2);
  }

  public int CompareTo(object obj)
  {
    return CompareTo((TestStruct)obj);
  }
}

If Class1 has an attribute named Attribute2 of type TestStruct, an ordinary custom method such as CompareToX can be called in OCL:

Class1.allInstances.Attribute2.CompareToX(
  Class1.allInstances->first.Attribute2)

Class1.allInstances.Attribute2 navigates the attribute from the instances of Class1. Collection navigation expands the values into one collection; see collection operator examples for this behavior.

Compare custom values with the OCL equality operator

Do not call CompareTo directly in OCL. CompareTo is a recognized comparison operation, and MDriven maps it to the OCL equality operator, =.

Use this expression instead:

Class1.allInstances.Attribute2 =
  (Class1.allInstances->first.Attribute2)

This explains why the direct call below produces an undefined-operation error:

Class1.allInstances.Attribute2.CompareTo(
  Class1.allInstances->first.Attribute2)

The error does not mean that the type cannot be used in OCL. It means that CompareTo has special equality semantics rather than being available as a normal OCL method call. Use another method name, such as CompareToX, when you need to invoke a custom comparison method explicitly.

Implement equality for the custom type

For attribute-type equality, MDriven uses IComparable.CompareTo when the type implements IComparable. Two values are equal when CompareTo returns 0. If the type does not implement IComparable, equality falls back to object.Equals.

Implement Equals consistently with CompareTo. Override GetHashCode as well. For the preceding example, add:

public override bool Equals(object obj)
{
  return CompareTo(obj) == 0;
}

public override int GetHashCode()
{
  return Int1 ^ Int2;
}

In this example, comparison is based on Int1 + Int2. Therefore, new TestStruct(1, 2) and new TestStruct(2, 1) compare as equal because both sums are 3. Your Equals implementation must use the same definition of equality as CompareTo; otherwise, OCL comparisons and .NET equality can produce conflicting results.

Persisting a custom attribute type

Using a native type in memory is separate from storing it in a database. If you persist a custom attribute type, you must provide persistence mapping for that type. The relevant mechanisms are AbstractSingleColumnAttribute, ISingleColumnAttribute mapping, and IDefaultReverseMapping.

Plan the stored representation before you make the attribute persistent. For example, a two-value structure may require a defined single-column representation and a corresponding reverse mapping back to the custom type.

OCL and EAL usage

OCL is a query language and expressions must not have side effects. Use it for constraints, derivations, ViewModel expressions, and other queries. EAL uses OCL-like syntax where an action needs to change data. See Learn OCL for where these languages are used.

Troubleshooting

Symptom Cause What to do
Undefined operation: CompareTo CompareTo is mapped to OCL =. Replace the method call with an equality expression, such as value1 = value2.
A method with another name, such as CompareToX, works Methods on the native type can be exposed to OCL; the special behavior is specific to CompareTo. Keep the custom method name when you need an explicit method call.
Equality does not match the intended business comparison CompareTo and Equals use different rules, or neither rule represents the intended equality. Define one equality rule and implement CompareTo, Equals, and GetHashCode consistently.
A custom attribute works in memory but cannot be stored No persistence mapping has been supplied for the native type. Implement the required custom-type persistence mapping.

See also