Blog Series: Model Driven Development with T4 templates – Part 2
Date: Monday, February 18, 2013 10:22 AM
Posted by: Nico Ploner
Category: T4
The second part of this blog series introduces the tangible Modeling Tools, a Visual Studio integrated designer for several UML-style diagram types, that can be used to create domain specific models. Later in this series we’re going to use a Persistence Model diagram (.tasl) to generate data classes and a basic UI from it using T4 templates.
Blog Series Overview
Part 1: Model Driven Development and Series Overview
Part 2: Create a Persistence Model using Tangible Modeling Tools
Part 3: Generating Domain Specific data objects using T4 and EntityFramework 5 CodeFirst
Part 4: Data Persistence and Versioning
Part 5: Generate a Basic UI using T4 and Windows Presentation Foundation
In this Part
Tangible Persistence Model Diagram
Create a Persistent Object Model
Tangible Modeling Tools
Our Modeling Tools extend your copy of Visual Studio 2010 or Visual Studio 2012 by a set of UML-style diagram types and a designer for creating and editing those diagrams. The following diagram types ship with tangible Modeling Tools:
All of those diagram types are intended to be used in a Model Driven Development process and model parts of the domain specific knowledge. Besides modeling the knowledge to communicate ideas between the stakeholders, the diagrams provide functionality for easily creating platform specific code using T4 templates.
For each diagram type there is a sample in our free T4 Template Gallery.
Tangible Persistence Model Diagram
In our blog series we’re going to use a tangible Persistence Model Diagram to visualize some domain specific knowledge and create data classes, a persistence layer and some basic user interface from it. So let’s have a closer look at the Persistence Model Diagram type:
First add a new .tasl file to your existing Visual Studio 2010 or Visual Studio 2012 project by right clicking the project and choosing “Add” > “New item” from the context menu. Select a “tangible Persistence Object Diagram” from the item category “tangible modeling tools” and name it e.g. “BlogSeries.tasl”.
Persistence Model Toolbox Items
Open the new .tasl-File in the designer and have a look at the Visual Studio Toolbox. The category “Persistent Object Model” provides you with items to build your domain model with.
- Persistent Object
A persistent object equals a class shape in a common class diagram. It represents a class of domain specific objects and contains properties and methods of those objects. A persistent object can have relations to other persistent objects or even inherit from an other persistent object. - Persistent Root Object
The persistent root object is a special kind of a persistent object. It represents the logical root of a network of persistent objects connected by containments and associations. The existence of a persistent root object is mandatory for each Persistence Model Diagram. It cannot inherit from another persistent object and can only be the source of associations and containments. - Inheritance
Two persistent objects can be connected via an inheritance item meaning that one of them is a specialization of the other. This relationship equals the specialization/generalization pattern of object oriented programming languages. - Property
A persistent object can contain an infinite number of properties. The minimum information a property is its name and the data type that property stores. - Method
As with properties, a persistent object can provide operations that may be executed on the persistent object. Methods must contain information about their name, the type of the return value and all parameters. - Association
An association connects two persistent objects. Associations can be thought of as a property on each persistent object participating this association that contains one or more instances of the other persistent object – depending on the multiplicity set in the association’s properties. - Containment
A containment is a special form of association between two persistent objects. The source of a containment (visualized by a blue diamond in the diagram) is considered “responsible” for the target object. It depends on the interpretation of the diagram what this “responsibility” means. Usually it means, the source creates instances of the target object and cares for their proper deletion. - Comment and Comment Link
For explanation purposes, any item on the Persistent Object Diagram can be annotated by comments. Just drag a comment item onto the designer surface and fill it with commentary information. To assign a comment to a specific item, connect them with a Comment Link.
Features
Besides positioning and connecting toolbox items on a canvas the persistence object model of the tangible Modeling tools provides some additional features: those are model validation, auto-naming and extensible properties.
Validation
When you first open a new Persistence Model Diagram in the designer, Visual Studio will complain about not having a root object inside the diagram in the Error List. Visual Studio will also notify you if your persistent object model lacks proper connectivity between persistent objects: e.g. each persistent object needs to be reachable from the persistent root object via containment relationships.
Auto-Naming
When creating associations, tangible Modeling Tools will automatically create proper navigation property names. So creating a one-to-many relationship between the persistent objects “Person” and “Car” will result in a navigation property named “Cars” in the “Person” object and a navigation property “Person” in the “Car” object.
These properties will be kept in sync – so if you decide to rename the class “Car” into “AutoMobile”, the navigation property “Cars” will be renamed to “AutoMobiles”. There’s one exception to this rule: if you rename the navigation property manually to e.g. “Autos” it won’t be changed automatically, even if you rename the class again.
Extensible Properties
Extensible properties are the way to augment standard diagram models with custom information. If you are missing the possibility to store information to a persistent model, tangible Modeling Tools allow you to create this possibility yourself:
Open the “DefinedProperties” collection of a Toolbox Item in the Stereotype Editor and add the desired property to the item (we’ll use that feature later).
Create a Persistent Object Model
Now that we know everything about the features of the persistent object model, we need to create a domain specific (yet rather simple) sample model with which we’re going to start our Model Driven Development Process.
The Scenario
I came up with a very minimalistic model of a bank in which a bank serves customers by providing accounts and cash cards. A bank customer can obtain one or many cash cards, each one granting access to a single account.
Here is a screenshot of the final model built with the persistent object model designer:
Steps to create the model
Root Object “Bank”
Add a Persistent Root Object to the diagram by dragging it from the Toolbox onto the designer canvas. Name this object “Bank” either by double-clicking its header or changing the “Name”-Property in the Properties Window.
Add a Property to the Persistent Root Object. This can be done by dropping a Property Item from the Toolbox onto the Persistent Root Object or right-clicking the Root Object and choose “Add” > “Property”. Set the Name of the Property to “Id” and its Type to “Int32”. This property will serve us as unique identifier for a given bank in the persistence layer.
The same way add a “Name” property to the “Bank” object as a human readable identifier for a given bank.
Customer object
Then drag a Persistent Object item onto the designer canvas and name it “Customer”. The customer object gets three properties: an “Id” property of the Int32-Type (same purpose as the Bank-Id-Property), a property “FirstName” and a property “LastName”, both typed “string”.
Now connect the persistent root object with the “Customer” object using a Containment relationship, because if a bank is removed from the market, there’s no need to keep track of what people were customers of that bank. Select the “Containment” item in the Toolbox and then drag a dotted line from the Persistent Root Object to the “Customer” object.
A blue line will be drawn between the two objects with a small diamond shape at the side of the Persistent Root Object, indicating that the bank is the source of this containment, held “responsible” for the “Customer” object. Next to the line the navigation property names and multiplicities are displayed: "Bank” and “One” on the side of the Root Object and “Customers” and “ZeroMany” at the other end.
That information is read like this: “A bank has zero or many customers” and will result in a property “Customers” at the “Bank” object containing a collection of “Customer” objects. The other way round it means “A customer belongs to a single bank” resulting in a property named “Bank” in the “Customer” object referencing the only “Bank” object that customer belongs to.
CashCard object
Add another Persistent Object to the diagram and name it “CashCard”. Give it three Properties: “Id” (Int32), “Expiration” (DateTime) and PIN (string). Connect it to the “Customer” object via another containment dragged from “Customer” to “CashCard”.
This may be interpreted as follows: If a customer quits the service of a bank, all his CashCards become invalid. There is no need for a containment connection directly between “Bank” and “CashCard”, because the “CashCard” object is reachable from the Persistent Root Object via the path “Bank” > “Customer” > “CashCard”.
In our specific domain a bank would not create cash cards without the need to give it to a customer.
Account object
A bank holds an arbitrary amount of accounts. So add a third Persistent Object to our model and name it “Account”. An account contains an identifier (add an “Id” property of type “Int32”), an account number (type “string”) and information about its current rate (type “double”).
Since the bank manages all the accounts, the “Account” object is connected to the root object via a containment relationship.
But between the objects “Account” and “CashCard” we’re going to use an Association connection. On the one hand because the “CashCard” object is already reachable from the Persistent Root Object and on the other hand, because a customer can still carry his cash card around, even if the account has been deleted. So connect the two objects with an association with the “Account” object as the source.
Marking Identifiers
All objects in our model have an “Id” property. But this property is not different to any other property in the same object. That’s why we want to decorate this property with a flag that states “This one is the identifier property”.
Now we’re going to use the Extensible Property feature mentioned earlier:
Click somewhere inside an empty area in the model designer so that the the Properties-Window shows the properties of the “PersistentObjectModel” and click on the “…” button of the “DefinedStereoTypes” property:
This will open the “StereoType Collection Editor”. Select the member “Property” in the list on the left and click the “…” button of its “DefinedProperties” property to open the “ExtensibleProperty Collection Editor”. Add a new extensible property and set its default value to “False”, its name to “Identifier” and the Type to “System.Boolean”.
That way a new property will appear in the Properties Window each time you select a property inside a Persistent Object named “Identifier” and expecting a value either “True” or “False”. By default it will be set to “False”.
Close the windows again and select the “Id” property of the “Bank” object. Look at the Properties window and change the “Identifier” property to “True”. Do the same to all “Id” properties of the model.
Congratulations! You just created your first domain specific model to serve as a basis for generating data objects and a user interface in a Model Driven Development Process.
Continuation
Based on this Model we’re going to continue the following parts of our blog series on Model Driven Development.
In part 3 we’re going to create data objects based on this model using a T4 template to automatically generate C# code classes. Part 4 will create a data access layer for this model and the last part will generate a basic UI to create and manipulate data defined in this domain specific banking model.