[DSL Tools] Reference relationships and compartment shapes
Presentation of the problem:
Deleting behaviour with compartments representing embeddings
Most of the time, in the DSL Tools, you map compartments in compartment shapes to embedding relationships.
And then, deleting a compartment item in the compartment shape indeed removes the model element which was displayed as this compartment item, which makes sense.
Deleting behaviour with compartments representing reference relationships
Now let's suppose you have are mapping a compartment not to an embedding, but to a reference relationship. You might think that deleting a compartment item will only delete the link between the instance represented by the compartment shape and the instance represented by the compartment item. But it turns out that it also deletes the instance represented by the compartment item.
There are scenarios, where you would like first behaviour. This posts explains why it is so, and how to proceed to have only the link deleted, not the target model element.
A case study: what it does, and what we would want
The domain model
- we have 2 domain classes ClassA and ClassB, linked thru a Reference relationship (many-many) named ClassAReferencesClassB
- ClassB is represented as a geometric shape ClassBShape
- ClassB is represented by a compartment shape ClassAShape, which displays the ClassBs referenced by the instance of ClassA through ClassAReferencesClassB
- the same ClassAReferencesClassB is also represented by a connector, so that we really see what is happening there.
Figure 1: the domain model (please, click the image to enlarge)
Opening the DSL Details tool window, and clicking on the mapping line between ClassA and ClassAShape, in the Compartment Maps tab, we use the path editor as we usually do and end-up with the following, which really means that in the Bs compartment, we are:
- requesting to represent ClassB instances, which we get though the ClassAReferencesClassB relationship navigating though the ClassB role (Displayed elements collection path)
- Then we want to display the Name of each ClassB (Display property).
Figure 2: The mapping between ClassA and the compartment shape representing it.
Running our designer - what it does
After transforming all templates, and running the editor, you create a ClassA , a ClassB , and connect them through the connector, in order to get this (the ClassB1 instance also appears in the compartment, since the relationship is mapped both to the compartment and the connector)
Figure 3: Running our designer - starting point
Now, let's try to delete ClassB1 from the compartment (Using the Del key or the contextual Delete command). You end-up with this:
- the ClassB1 represented instance was deleted (after all the Delete command was targeting it), removing the link, of course
- consequently the ClassB1 shape was deleted
Figure 3: Running our designer - what Delete does on the compartment item
Running our designer - What we would like
That said. You were maybe expecting that, considering you were using a Reference relationship and not an embedding, you would end-up with only deleting the link between ClassA1 and ClassB1 and not the ClassB1 instance. It turns out that this scenario is of interest, but this is not what you requested. You really sent the Delete command to the ClassB1 instance, hence the result.
How to get what we want
In fact, to tell you the truth, I thought myself this behaviour was a bug :-), until Stuart explained me about the command being directed to the ClassBs instances and not to the link. Then, you can very easily achieve our desired behaviour specifying the right things in the DSL Details window on the shape map (and not writing any custom code)
Here is how we should proceed.
Still in the Compartment Maps tab of our mapping between ClassA and ClassAShape, we need to express that we want to deal not with ClassB instances but with a collection of ClassAReferencesClassBlinks form the instance of ClassA represented by the compartment shape to the related ClassB instances.
The Displayed elements collection path should, therefore be ClassAReferencesClassB.ClassB
This can be understood as the same code construct as ClassAReferencesClassB.GetLinksToClassB(ClassA1) which returns collection of ClassAReferencesClassB. This is really an instance of the link that will be presented as a compartment item, and thus, deleting it will delete the link, not the targeted ClassB.
Now, we need to specify what to display (namely the Name property of the ClassB instance accessed through the link). For that, given an instance of ClassAReferencesClassB, we need to get an instance of ClassB (just in order to access its property). We express this in the Path to display property field as ClassAReferencesClassB!ClassB which means getting the ClassB property of the ClassAReferencesClassB instance, that is getting a ClassB instance.
The last step is to provide the Display property, here Name
Figure 4: how to express we want to deal with links
Running our designer - We get what we want
After transforming all templates, and running the designer the first thing is you get exactly the same appearance as before (even if now the compartment items represent links and not model element instances). This is no surprise because we did all we could for that, but it's work noting it
Figure 5: Running our new designer - apparently this is like before
But this, time, deleting the ClassB1 compartment item, we end up with the following expected result:
Figure 6: Running our new designer - the delete command now delete the link, not the targeted shape
In this post, we learnt why, when mapping a compartment to a reference relationship, deleting compartment items deletes the targeted model element with the usual mapping, and how to change the mapping so that it only deletes the link.