Introduction
Model Oriented Development (MOD) is a technique that allows you to utilize a model for development purposes at any point in the development process. You translate model information into source code and/or utilize the model directly during the course of development. This doesn't imply any particular process or technology. How you represent and utilize your model is completely up to you.
A model to be used for MOD (or software development in general) can be described as having the following characteristics:
- Model Structure - The model structure defines the "rules" or schema by which corresponding models can be organized and built. For example, in a generic entity relationship model, the model structure would include constructs such as Entity, Relationship, and Property.
- Model Data - The model data defines particular instances of the model structure, and gives concrete meaning to the model for a particular purpose. For example, in a generic entity relationship model, the model data could include instances of Entity such as Customer or Order, and instances of Property such as First Name (for Customer) and Order Total (for Order).
Any type of model (UML, Microsoft Entity Framework, etc.), whether simple or complex, can be described in terms of model structure and model data.
Modeling can be described as the process of populating your chosen model structure with model data, in accordance with your requirements and needs for designing and developing a particular system. Modeling tools often provide means of creating and maintaining model data through visual constructs such as diagrams. This article does not cover the modeling process, and will just present model data in a raw format.
Leveraging the model - with MOD, you typically leverage a model to create and maintain code based on the data outlined in that model, your system requirements, and your coding best practices. To utilize a model in the most effective way for model oriented development:
- You need to be able to have complete visibility to the model structure
- You need to be able to "walk" through model data in many conceivable ways:
- General browsing of model data based on the model structure
- Browsing to get parent, children, or other related information for an instance of model data
- Search for model data based on criteria
- You need to be able to indicate and deal with exceptions for instances in the model data that doesn't conform to general rules you have outlined
- You need to be able to seamlessly integrate your generated model oriented code with your custom code (model oriented or otherwise)
In this article, we will cover how you can utilize model structures and data for model oriented development. We will create two "made up" examples of simple model structures and data, and show how you can utilize this information to effectively generate and maintain code in a model oriented way.
Background
Mo+ will be the choice for utilizing custom model structures and data in this article, since Mo+ is specifically designed to handle and recognize model structures and data of your choosing. The Mo+ model oriented programming language and the Mo+ Solution Builder IDE for model oriented development was introduced in this Code Project article. The intent of this article is how to utilize model structures and data in general for MOD. Mo+ models and templates will be presented, but this article is not a Mo+ language or tool how to. However, you can apply the technique outlined in this article with other modeling and code generation tools to various degrees. If you are trying to use Mo+, the above article also has a Learn More section with additional information to get you started.
The model structures will be displayed as a UML class diagrams, where:
- Classes represent objects in the model structure
- Members represent properties of objects in the model structure
- Associations represent parent-child relationships in the model structure
The model data for both examples will be populated from the Northwind (SQL Server or MySQL) database schema.
The generated code will be in XML and C#.
An Example Model - Foundations and Expansions
We are going to totally make up a simple model here. Let's say that we want our models to consist of basic building blocks called foundations and higher level things called expansions that can utilize foundations and other expansions.
Model Structure
Consider the following diagram that represents our intended model structure:
The rules for this model structure are pretty simple:
- A Foundation is a basic building block that is identified by a FoundationID and described by a FoundationName.
- An Expansion is a higher level building block that is identified by an ExpansionID and described by an ExpansionName. An Expansion can be further described by free form Tags.
- A FoundationLayer expands a particular Expansion to include a particular Foundation building block. A FoundationLayer is identified by a FoundationLayerID and identifies the reference to the corresponding Foundation via ReferencedFoundationID.
- An ExpansionLayer expands a particular Expansion to include another Expansion. An ExpansionLayer is identified by an ExpansionLayerID and identifies the reference to the corresponding Expansion via ReferencedExpansionID.
- An Expansion can consist of zero or more FoundationLayers.
- An Expansion can consist of zero ro more ExpansionLayers
Model Data
To actually use our model structure for MOD, we need to populate a model with data that conforms to the structure outlined above.
We are going to use the Northwind database schema as a source for model data, and populate the model as such:
- If a table has no foreign keys, it is added to the model as a Foundation
- The table name (slightly massaged) becomes the FoundationName
- The FoundationID is generated
- If a table has foreign keys, it is added to the model as an Expansion
- The table name (slightly massaged) becomes the ExpansionName
- The ExpansionID is generated
- For each foreign key
- If the foreign key is to a Foundation, the key is added to the model as a FoundationLayer
- If the foreign key is to an Expansion, the key is added to the model as an ExpansionLayer
The following tree view illustrates this model data in raw form:
Notice that particular foundations include things such as Category and Customer, and particular expansions include things such as Employee and Order.
If you are using Mo+, load the FoundationExpansionModel.xml solution model from the example download, which will create this model structure and populate it if you have a connection to the Northwind (or other sql server) database. The code templates described in this example will also be directly available.
MOD - Using the Model to Generate XML
We are going use our populated model to generate an XML file of foundations and expansions. Within code templates, we will walk through the model in various ways, utilizing the model data (combined with raw template text) to generate the XML file contents.
General Browsing of Model Data
At the very least, you need to be able to browse through the model data to get all of the instances for any given object in the model structure. Below, we create some basic XML by browsing through each Foundation and Expansion in our model (seen within the foreach statements at lines 4 and 12):
Below is the XML generated with the Northwind model data. Nodes for foundations and expansions were generated, with their corresponding names. (Mo+ template in example download is called FEBrowseOnly):
<Model>
<Foundations>
<Foundation Name="CustomerDemographic"/>
<Foundation Name="Category"/>
<Foundation Name="Customer"/>
<Foundation Name="Region"/>
<Foundation Name="Shipper"/>
<Foundation Name="Supplier"/>
</Foundations>
<Expansions>
<Expansion Name="CustomerCustomerDemo"/>
<Expansion Name="Employee"/>
<Expansion Name="EmployeeTerritory"/>
<Expansion Name="OrderDetail"/>
<Expansion Name="Order"/>
<Expansion Name="Product"/>
<Expansion Name="Territory"/>
</Expansions>
</Model>
Accessing Child Model Data
You need to be able to access child information for any particular instance of your model data. In this case, we want to access all FoundationLayers and ExpansionLayers under a particular Expansion. Below, we browse through child FoundationLayers and ExpansionLayers for the current Expansion (seen within the foreach statements at lines 17 and 25). We want to generate FoundationLayer and ExpansionLayer child nodes:
Below is the XML generated with child layer data under each expansion. (Mo+ template in example download is called FEBrowseChildren):
<Model>
<Foundations>
<Foundation Name="CustomerDemographic"/>
<Foundation Name="Category"/>
<Foundation Name="Customer"/>
<Foundation Name="Region"/>
<Foundation Name="Shipper"/>
<Foundation Name="Supplier"/>
</Foundations>
<Expansions>
<Expansion Name="CustomerCustomerDemo">
<FoundationLayers>
<FoundationLayer Reference="3">
<FoundationLayer Reference="4">
</FoundationLayers>
<ExpansionLayers>
</ExpansionLayers>
</Expansion>
<Expansion Name="Employee">
<FoundationLayers>
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Reference="5">
</ExpansionLayers>
</Expansion>
<Expansion Name="EmployeeTerritory">
<FoundationLayers>
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Reference="5">
<ExpansionLayer Reference="13">
</ExpansionLayers>
</Expansion>
<Expansion Name="OrderDetail">
<FoundationLayers>
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Reference="8">
<ExpansionLayer Reference="9">
</ExpansionLayers>
</Expansion>
<Expansion Name="Order">
<FoundationLayers>
<FoundationLayer Reference="4">
<FoundationLayer Reference="11">
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Reference="5">
</ExpansionLayers>
</Expansion>
<Expansion Name="Product">
<FoundationLayers>
<FoundationLayer Reference="1">
<FoundationLayer Reference="12">
</FoundationLayers>
<ExpansionLayers>
</ExpansionLayers>
</Expansion>
<Expansion Name="Territory">
<FoundationLayers>
<FoundationLayer Reference="10">
</FoundationLayers>
<ExpansionLayers>
</ExpansionLayers>
</Expansion>
</Expansions>
</Model>
Accessing Parent Model Data
You also need to be able to have direct access to any parent data (and that parent's parent data, etc.) for any particular model data instance. Our model structure is pretty shallow, but let's add a description to the FoundationLayer and ExpansionLayer nodes with the name of the parent Expansion. So, for the current FoundationLayer or ExpansionLayer instance, we grab the name from that instance's parent Expansion (seen at lines 20 and 29 in with the ../ syntax):
Below is the XML generated with Description attributes containing the name of the parent Expansion. (Mo+ template in example download is called FEBrowseChildrenAccessParent):
<Model>
<Foundations>
<Foundation Name="CustomerDemographic"/>
<Foundation Name="Category"/>
<Foundation Name="Customer"/>
<Foundation Name="Region"/>
<Foundation Name="Shipper"/>
<Foundation Name="Supplier"/>
</Foundations>
<Expansions>
<Expansion Name="CustomerCustomerDemo">
<FoundationLayers>
<FoundationLayer Description="Provides a layer for CustomerCustomerDemo to 3.">
<FoundationLayer Description="Provides a layer for CustomerCustomerDemo to 4.">
</FoundationLayers>
<ExpansionLayers>
</ExpansionLayers>
</Expansion>
<Expansion Name="Employee">
<FoundationLayers>
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Description="Provides a layer for Employee to 5.">
</ExpansionLayers>
</Expansion>
<Expansion Name="EmployeeTerritory">
<FoundationLayers>
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Description="Provides a layer for EmployeeTerritory to 5.">
<ExpansionLayer Description="Provides a layer for EmployeeTerritory to 13.">
</ExpansionLayers>
</Expansion>
<Expansion Name="OrderDetail">
<FoundationLayers>
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Description="Provides a layer for OrderDetail to 8.">
<ExpansionLayer Description="Provides a layer for OrderDetail to 9.">
</ExpansionLayers>
</Expansion>
<Expansion Name="Order">
<FoundationLayers>
<FoundationLayer Description="Provides a layer for Order to 4.">
<FoundationLayer Description="Provides a layer for Order to 11.">
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Description="Provides a layer for Order to 5.">
</ExpansionLayers>
</Expansion>
<Expansion Name="Product">
<FoundationLayers>
<FoundationLayer Description="Provides a layer for Product to 1.">
<FoundationLayer Description="Provides a layer for Product to 12.">
</FoundationLayers>
<ExpansionLayers>
</ExpansionLayers>
</Expansion>
<Expansion Name="Territory">
<FoundationLayers>
<FoundationLayer Description="Provides a layer for Territory to 10.">
</FoundationLayers>
<ExpansionLayers>
</ExpansionLayers>
</Expansion>
</Expansions>
</Model>
Searching for Model Data by Criteria
We want to replace the numeric values in our ExpansionLayer and FoundationLayer descriptions with the actual name of the referenced Expansions and Foundations. But our simple little model structure doesn't have a direct link from the layers to their references. So, how do we get that data? We need to search for it!
Below, we search for the corresponding Foundation and Expansion by relevant id to get the names (as seen in the with statements with Find clauses at lines 19 and 31):
Below is the XML generated with the referenced names. (Mo+ template in example download is called FEBrowseAndSearch):
<Model>
<Foundations>
<Foundation Name="CustomerDemographic"/>
<Foundation Name="Category"/>
<Foundation Name="Customer"/>
<Foundation Name="Region"/>
<Foundation Name="Shipper"/>
<Foundation Name="Supplier"/>
</Foundations>
<Expansions>
<Expansion Name="CustomerCustomerDemo">
<FoundationLayers>
<FoundationLayer Name="CustomerDemographic" Description="Provides a layer for CustomerCustomerDemo to CustomerDemographic.">
<FoundationLayer Name="Customer" Description="Provides a layer for CustomerCustomerDemo to Customer.">
</FoundationLayers>
<ExpansionLayers>
</ExpansionLayers>
</Expansion>
<Expansion Name="Employee">
<FoundationLayers>
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Name="Employee" Description="Provides a layer for Employee to Employee.">
</ExpansionLayers>
</Expansion>
<Expansion Name="EmployeeTerritory">
<FoundationLayers>
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Name="Employee" Description="Provides a layer for EmployeeTerritory to Employee.">
<ExpansionLayer Name="Territory" Description="Provides a layer for EmployeeTerritory to Territory.">
</ExpansionLayers>
</Expansion>
<Expansion Name="OrderDetail">
<FoundationLayers>
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Name="Order" Description="Provides a layer for OrderDetail to Order.">
<ExpansionLayer Name="Product" Description="Provides a layer for OrderDetail to Product.">
</ExpansionLayers>
</Expansion>
<Expansion Name="Order">
<FoundationLayers>
<FoundationLayer Name="Customer" Description="Provides a layer for Order to Customer.">
<FoundationLayer Name="Shipper" Description="Provides a layer for Order to Shipper.">
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Name="Employee" Description="Provides a layer for Order to Employee.">
</ExpansionLayers>
</Expansion>
<Expansion Name="Product">
<FoundationLayers>
<FoundationLayer Name="Category" Description="Provides a layer for Product to Category.">
<FoundationLayer Name="Supplier" Description="Provides a layer for Product to Supplier.">
</FoundationLayers>
<ExpansionLayers>
</ExpansionLayers>
</Expansion>
<Expansion Name="Territory">
<FoundationLayers>
<FoundationLayer Name="Region" Description="Provides a layer for Territory to Region.">
</FoundationLayers>
<ExpansionLayers>
</ExpansionLayers>
</Expansion>
</Expansions>
</Model>
Dealing with Exceptions
OK, walking through and searching model data in various ways to generate the code you want is all well and good. But, inevitably the code you want doesn't always map neatly and consistently to your model data, there are always exceptions, and you need to manage those exceptions.
One way to deal with exceptions is to "tag" various particular instances of your model data with any number of terms, and do something else based on the presence (or absence) of those tags. We tagged the CustomerDemographic Foundation instance and the CustomerCustomerDemo Expansion instance with "Ignore", since we decided not to generate these nodes in our XML. Below, we skip ignored Foundations and Expansions (as seen with the where clauses on lines 4 and 12):
Below is the XML generated with the ignored CustomerDemographic and CustomerCustomerDemo nodes removed. (Mo+ template in example download is called FEExceptions):
<Model>
<Foundations>
<Foundation Name="Category"/>
<Foundation Name="Customer"/>
<Foundation Name="Region"/>
<Foundation Name="Shipper"/>
<Foundation Name="Supplier"/>
</Foundations>
<Expansions>
<Expansion Name="Employee">
<FoundationLayers>
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Name="Employee" Description="Provides a layer for Employee to Employee.">
</ExpansionLayers>
</Expansion>
<Expansion Name="EmployeeTerritory">
<FoundationLayers>
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Name="Employee" Description="Provides a layer for EmployeeTerritory to Employee.">
<ExpansionLayer Name="Territory" Description="Provides a layer for EmployeeTerritory to Territory.">
</ExpansionLayers>
</Expansion>
<Expansion Name="OrderDetail">
<FoundationLayers>
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Name="Order" Description="Provides a layer for OrderDetail to Order.">
<ExpansionLayer Name="Product" Description="Provides a layer for OrderDetail to Product.">
</ExpansionLayers>
</Expansion>
<Expansion Name="Order">
<FoundationLayers>
<FoundationLayer Name="Customer" Description="Provides a layer for Order to Customer.">
<FoundationLayer Name="Shipper" Description="Provides a layer for Order to Shipper.">
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Name="Employee" Description="Provides a layer for Order to Employee.">
</ExpansionLayers>
</Expansion>
<Expansion Name="Product">
<FoundationLayers>
<FoundationLayer Name="Category" Description="Provides a layer for Product to Category.">
<FoundationLayer Name="Supplier" Description="Provides a layer for Product to Supplier.">
</FoundationLayers>
<ExpansionLayers>
</ExpansionLayers>
</Expansion>
<Expansion Name="Territory">
<FoundationLayers>
<FoundationLayer Name="Region" Description="Provides a layer for Territory to Region.">
</FoundationLayers>
<ExpansionLayers>
</ExpansionLayers>
</Expansion>
</Expansions>
</Model>
Integrating with Customizations
Finally, it is essential that you have the ability to seamlessly integrate generated model oriented code with your custom code. With MOD, you may have introduced the model late in your development lifecycle and may be incorporating bits and pieces from the model over time. In any case, you'll always want to maintain your high quality and essential custom code.
If your generated and custom code are in separate files and know about each other's integration points (and that is usually ideal), then integration is usually no big deal. But what if customizations and generated code need to be in the same file? In our case, we want to integrate customizations into our generated xml file.
One way to manage this is to be able to define customization begin and end points. Within those areas in the generated code, custom code can be maintained, even after the generated code is updated.
We want to insert some custom nodes for our Employee Expansion instance. So, we tagged this instance as "CustomNodes", and modified our template to create customization points (as comments) for Expansions tagged in this way (see lines 16-21):
Below is the XML generated with the customization points for Employee. Note that the node called CustomNode is a piece of inserted custom code. This customization is maintained when the file is regenerated. (Mo+ template in example download is called FEIntegrateCustomizations, see the output area for this template which defines customization begin and end points and rules for updating file. This template is called when you click on "Update Output Solution" for this solution.):
<Model>
<Foundations>
<Foundation Name="Category"/>
<Foundation Name="Customer"/>
<Foundation Name="Region"/>
<Foundation Name="Shipper"/>
<Foundation Name="Supplier"/>
</Foundations>
<Expansions>
<Expansion Name="Employee">
<CustomNode Name="This is a test!" />
<FoundationLayers>
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Name="Employee" Description="Provides a layer for Employee to Employee.">
</ExpansionLayers>
</Expansion>
<Expansion Name="EmployeeTerritory">
<FoundationLayers>
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Name="Employee" Description="Provides a layer for EmployeeTerritory to Employee.">
<ExpansionLayer Name="Territory" Description="Provides a layer for EmployeeTerritory to Territory.">
</ExpansionLayers>
</Expansion>
<Expansion Name="OrderDetail">
<FoundationLayers>
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Name="Order" Description="Provides a layer for OrderDetail to Order.">
<ExpansionLayer Name="Product" Description="Provides a layer for OrderDetail to Product.">
</ExpansionLayers>
</Expansion>
<Expansion Name="Order">
<FoundationLayers>
<FoundationLayer Name="Customer" Description="Provides a layer for Order to Customer.">
<FoundationLayer Name="Shipper" Description="Provides a layer for Order to Shipper.">
</FoundationLayers>
<ExpansionLayers>
<ExpansionLayer Name="Employee" Description="Provides a layer for Order to Employee.">
</ExpansionLayers>
</Expansion>
<Expansion Name="Product">
<FoundationLayers>
<FoundationLayer Name="Category" Description="Provides a layer for Product to Category.">
<FoundationLayer Name="Supplier" Description="Provides a layer for Product to Supplier.">
</FoundationLayers>
<ExpansionLayers>
</ExpansionLayers>
</Expansion>
<Expansion Name="Territory">
<FoundationLayers>
<FoundationLayer Name="Region" Description="Provides a layer for Territory to Region.">
</FoundationLayers>
<ExpansionLayers>
</ExpansionLayers>
</Expansion>
</Expansions>
</Model>
Another Example - A Class Based Model
We are going to go through the same set of steps with a completely different kind of model to show how the process is the same. We often use MOD to generated model oriented software (often in an object oriented language), so let's make up a little model that we can use to model classes.
Model Structure
Consider the following diagram that represents our intended class model structure:
The rules for this simple class model structure are also pretty simple:
- A Class represents a class in an object oriented language. A Class is identified by a ClassID, and named by a ClassName. A Class can be further described by free form Tags.
- An Attribute represents a simple type member of a class such as a string or numeric field or property. An Attribute is identified by an AttributeID, and named by an AttributeName. An Attribute holds a String or Numeric value as a ValueType enumeration(we are keeping this simple with only 2 data types).
- A Reference represents a member of a class that refers to an instance of another class. A Reference is identified by a ReferenceID, and named by a ReferenceName. Reference refers to an instance of a class via ReferencedClassID.
- A Class can consist of zero or more Attributes.
- A Class can consist of zero or more References.
Model Data
Again, we are going to use the Northwind database schema as a source for model data. This time, we are going to populate the model as such:
- Each table becomes a Class
- The table name (slightly massaged) becomes the ClassName
- The ClassID is generated
- Each column becomes an Attribute within the corresponding Class
- The column name (slightly massaged) becomes the AttributeName
- The column data types becomes the ValueType (simplified to String or Numeric)
- The AttributeID is generated
- Each foreign key becomes a Reference
- The ReferenceName is based on the referred to class name
- The ReferencedClassID is the id of the class that was created based on the referenced table
- The ReferenceID is generated
The following tree view illustrates this model data in raw form:
Notice that things such as Customer, Employee, and Order are classes. The EmployeeTerritory class is expanded to show the attributes (EmployeeID and TerritoryID) and references (to Employee and Territory).
If you are using Mo+, load the ClassModel.xml solution model from the example download, which will create this model structure and populate it if you have a connection to the Northwind (or other sql server) database. The code templates described in this example will also be directly available.
MOD - Using the Model to Generate C#
We are going use our populated model to generate C# classes and members within those classes. Within code templates, we will walk through the model in various ways, utilizing the model data (combined with raw template text) to generate the C# classes and their details.
General Browsing of Model Data
Again, you need to be able to browse through the model data to get all of the instances for any given object in the model structure. Below, we create the classes by browsing through each Class in our model (seen within the foreach statement at line 2):
Below is the set of C# classes generated with the Northwind model data. The classes were generated, with their corresponding names. (Mo+ template in example download is called ClassBrowseOnly):
public class CustomerCustomerDemo
{
}
public class CustomerDemographic
{
}
public class Category
{
}
public class Customer
{
}
public class Employee
{
}
public class EmployeeTerritory
{
}
public class OrderDetail
{
}
public class Order
{
}
public class Product
{
}
public class Region
{
}
public class Shipper
{
}
public class Supplier
{
}
public class Territory
{
}
Accessing Child Model Data
As an example of accessing child data, we want to access all Attributes for a particular Class. Below, we browse through child Attributes for the current Class (seen within the foreach statement at line 7). We want to generate the attributes as get/set properties:
Below is the set of C# classes generated with basic get/set properties (some details in the generated code from here on out are blocked out with an ellipsis). (Mo+ template in example download is called ClassBrowseChildren):
public class CustomerCustomerDemo
{
public string CustomerID { get; set; }
public string CustomerTypeID { get; set; }
}
public class CustomerDemographic
{
public string CustomerTypeID { get; set; }
public string CustomerDesc { get; set; }
}
public class Category
{
public string Picture { get; set; }
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public string Description { get; set; }
}
public class Customer
{
public string CustomerID { get; set; }
public string CompanyName { get; set; }
public string ContactName { get; set; }
.
.
.
}
.
.
.
public class Order
{
public int OrderID { get; set; }
public string CustomerID { get; set; }
public int EmployeeID { get; set; }
.
.
.
}
public class Product
{
public int ProductID { get; set; }
public string ProductName { get; set; }
.
.
.
}
.
.
.
Accessing Parent Model Data
For accessing parent model data, again our model structure is pretty shallow, but let's add some comments, and have the Attribute property comments include the parent Class name (seen at line 14 with Class. notation):
Below is the updated set of C# classes with comments. (Mo+ template in example download is called ClassBrowseChildrenAccessParent):
public class CustomerCustomerDemo
{
public string CustomerID { get; set; }
public string CustomerTypeID { get; set; }
}
public class CustomerDemographic
{
public string CustomerTypeID { get; set; }
public string CustomerDesc { get; set; }
}
public class Category
{
public string Picture { get; set; }
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public string Description { get; set; }
}
public class Customer
{
public string CustomerID { get; set; }
public string CompanyName { get; set; }
public string ContactName { get; set; }
.
.
.
}
.
.
.
public class Order
{
public int OrderID { get; set; }
public string CustomerID { get; set; }
public int EmployeeID { get; set; }
.
.
.
}
public class Product
{
public int ProductID { get; set; }
public string ProductName { get; set; }
.
.
.
}
.
.
.
Searching for Model Data by Criteria
Now we want to add our References as get/set properties for the class. Again our simple little model structure doesn't have a direct link from the references to their classes. So, we will have to search for the references.
We add browsing References to add the reference get/set properties (as seen in lines 19-28), and we search for the corresponding class by id to get the proper name for the data type and comment (as seen in the with statement with Find clause at line 21):
Below is the updated set of C# classes with the Reference get/set properties. (Mo+ template in example download is called ClassBrowseAndSearch):
public class CustomerCustomerDemo
{
public string CustomerID { get; set; }
public string CustomerTypeID { get; set; }
public CustomerDemographic CustomerDemographic { get; set; }
public Customer Customer { get; set; }
}
public class CustomerDemographic
{
public string CustomerTypeID { get; set; }
public string CustomerDesc { get; set; }
}
public class Category
{
public string Picture { get; set; }
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public string Description { get; set; }
}
public class Customer
{
public string CustomerID { get; set; }
public string CompanyName { get; set; }
public string ContactName { get; set; }
.
.
.
}
.
.
.
public class EmployeeTerritory
{
public int EmployeeID { get; set; }
public string TerritoryID { get; set; }
public Employee Employee { get; set; }
public Territory Territory { get; set; }
}
.
.
.
Dealing with Exceptions
Again, we choose to deal with exceptions by tagging. We tagged the CustomerDemographic and CustomerCustomerDemo Class instances with "Ignore", since we decided not to generate these classes. Below, we skip ignored Classes (as seen with the where clause on line 2):
Below is the updated set of C# classes with the ignored CustomerDemographic and CustomerCustomerDemo classes removed. (Mo+ template in example download is called ClassExceptions):
public class Category
{
public string Picture { get; set; }
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public string Description { get; set; }
}
public class Customer
{
public string CustomerID { get; set; }
public string CompanyName { get; set; }
public string ContactName { get; set; }
.
.
.
}
.
.
.
public class EmployeeTerritory
{
public int EmployeeID { get; set; }
public string TerritoryID { get; set; }
public Employee Employee { get; set; }
public Territory Territory { get; set; }
}
.
.
.
Integrating with Customizations
Again, we will define customization begin and end points to integrate some tricky customizations into our generated classes. Within those customization points (or protected areas), we can insert and maintain custom code.
We want the ability to add some custom code for some get/set properties. So, we tagged the (Category Class) Picture Attribute instance as "CustomGetSet", and modified our template to create customization points (as C# regions) for Attributes tagged in this way (see lines 15-37):
Below is the updated C# classes generated with the customization points for the Picture get/set property. Note that the getter and setter for Picture contains some custom comments inside the protected area regions. These customizations are maintained when the file is regenerated. (Mo+ template in example download is called ClassIntegrateCustomizations, see the output area for this template which defines customization begin and end points and rules for updating file. This template is called when you click on "Update Output Solution" for this solution.):
public class Category
{
private string picture
public string Picture
{
get
{
#region protected
#endregion protected
return picture;
}
set
{
picture = value;
#region protected
#endregion protected
}
}
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public string Description { get; set; }
}
public class Customer
{
public string CustomerID { get; set; }
public string CompanyName { get; set; }
.
.
.
}
.
.
.
public class EmployeeTerritory
{
public int EmployeeID { get; set; }
public string TerritoryID { get; set; }
public Employee Employee { get; set; }
public Territory Territory { get; set; }
}
.
.
.
In Summary
In short, for effective model oriented development (MOD), you need complete and easy access to your model's structure and data, you need to be able to manage exceptions, and you need to seamlessly integrate your custom code with your model oriented code.
Hopefully this article has provided you with some food for thought in taking a deeper look at models in terms of structure and data. Whether you choose to create your own model structures or use existing standardized structures, I hope that the examples here give you insight on effectively utilizing your model structures and data for effective model oriented development.
In addition, I hope you try Mo+ and the Mo+ Solution Builder to fully utilize incorporating a model oriented approach to your development. Mo+ has a built in flexible generic entity-relationship type of model structure, but it also allows you to create and use your own model structures (or recreate other standardized structures if you choose). The free, open source product is available at moplus.codeplex.com. In addition to the product, this site contains sample packs for building more complete models and generating complete working applications. Video tutorials and other materials are also available at this site. The Mo+ Solution Builder also contains extensive on board help.
Become a Member!
The Mo+ community gets additional support, and contributes to the evolution of Mo+ via the web site at https://modelorientedplus.com. Being a member gives Mo+ users additional benefits such as additional forum support, member contributed tools, and the ability to vote on and/or contribute to the direction of Mo+. Also, we will be running monthly contests for members, where you can win $ for developing solutions using Mo+.
If you are the least bit interested in efficient model oriented software development, please sign up as a member. It's free, and you won't get spam email!