Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

Utilizing Model Structures and Data Effectively for Model Oriented Development

4.85/5 (14 votes)
1 Mar 2017CPOL16 min read 16.9K   154  
Exploring ways to make direct use of model structures and data to powerfully augment software development with a model oriented approach.

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:

Image 1

The rules for this model structure are pretty simple:

  • 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:

Image 2

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):

Image 3

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):

XML
<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:

Image 4

Below is the XML generated with child layer data under each expansion.  (Mo+ template in example download is called FEBrowseChildren):

XML
<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):

Image 5

Below is the XML generated with Description attributes containing the name of the parent Expansion.  (Mo+ template in example download is called FEBrowseChildrenAccessParent):

XML
<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):

Image 6

Below is the XML generated with the referenced names.  (Mo+ template in example download is called FEBrowseAndSearch):

XML
<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):

Image 7

Below is the XML generated with the ignored CustomerDemographic and CustomerCustomerDemo nodes removed.  (Mo+ template in example download is called FEExceptions):

XML
<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):

Image 8

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.):

XML
<Model>
    <Foundations>
        <Foundation Name="Category"/>
        <Foundation Name="Customer"/>
        <Foundation Name="Region"/>
        <Foundation Name="Shipper"/>
        <Foundation Name="Supplier"/>
    </Foundations>
    <Expansions>
        <Expansion Name="Employee">
            <!-- region protected -->
            <CustomNode Name="This is a test!" />
            <!-- endregion protected -->
            <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:

Image 9

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:

Image 10

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):

Image 11

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):

C#
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:

Image 12

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):

C#
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):

Image 13

Below is the updated set of C# classes with comments.  (Mo+ template in example download is called ClassBrowseChildrenAccessParent):

C#
/// <summary>
/// This class holds data for CustomerCustomerDemo elements.
/// </summary>
public class CustomerCustomerDemo
{
    // Provide access to CustomerID data for the corresponding CustomerCustomerDemo instance.
    public string CustomerID { get; set; }
    
    // Provide access to CustomerTypeID data for the corresponding CustomerCustomerDemo instance.
    public string CustomerTypeID { get; set; }
    
}

/// <summary>
/// This class holds data for CustomerDemographic elements.
/// </summary>
public class CustomerDemographic
{
    // Provide access to CustomerTypeID data for the corresponding CustomerDemographic instance.
    public string CustomerTypeID { get; set; }
    
    // Provide access to CustomerDesc data for the corresponding CustomerDemographic instance.
    public string CustomerDesc { get; set; }
    
}

/// <summary>
/// This class holds data for Category elements.
/// </summary>
public class Category
{
    // Provide access to Picture data for the corresponding Category instance.
    public string Picture { get; set; }
    
    // Provide access to CategoryID data for the corresponding Category instance.
    public int CategoryID { get; set; }
    
    // Provide access to CategoryName data for the corresponding Category instance.
    public string CategoryName { get; set; }
    
    // Provide access to Description data for the corresponding Category instance.
    public string Description { get; set; }
    
}

/// <summary>
/// This class holds data for Customer elements.
/// </summary>
public class Customer
{
    // Provide access to CustomerID data for the corresponding Customer instance.
    public string CustomerID { get; set; }
    
    // Provide access to CompanyName data for the corresponding Customer instance.
    public string CompanyName { get; set; }
    
    // Provide access to ContactName data for the corresponding Customer instance.
    public string ContactName { get; set; }
    
    .
    .
    .
    
}

.
.
.

/// <summary>
/// This class holds data for Order elements.
/// </summary>
public class Order
{
    // Provide access to OrderID data for the corresponding Order instance.
    public int OrderID { get; set; }
    
    // Provide access to CustomerID data for the corresponding Order instance.
    public string CustomerID { get; set; }
    
    // Provide access to EmployeeID data for the corresponding Order instance.
    public int EmployeeID { get; set; }
    
    .
    .
    .
    
}

/// <summary>
/// This class holds data for Product elements.
/// </summary>
public class Product
{
    // Provide access to ProductID data for the corresponding Product instance.
    public int ProductID { get; set; }
    
    // Provide access to ProductName data for the corresponding Product instance.
    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):

Image 14

Below is the updated set of C# classes with the Reference get/set properties.  (Mo+ template in example download is called ClassBrowseAndSearch):

C#
/// <summary>
/// This class holds data for CustomerCustomerDemo elements.
/// </summary>
public class CustomerCustomerDemo
{
    // Provide access to CustomerID data for the corresponding CustomerCustomerDemo instance.
    public string CustomerID { get; set; }
    
    // Provide access to CustomerTypeID data for the corresponding CustomerCustomerDemo instance.
    public string CustomerTypeID { get; set; }
    
    // Provide reference to corresponding CustomerDemographic instance.
    public CustomerDemographic CustomerDemographic { get; set; }
    
    // Provide reference to corresponding Customer instance.
    public Customer Customer { get; set; }
    
}

/// <summary>
/// This class holds data for CustomerDemographic elements.
/// </summary>
public class CustomerDemographic
{
    // Provide access to CustomerTypeID data for the corresponding CustomerDemographic instance.
    public string CustomerTypeID { get; set; }
    
    // Provide access to CustomerDesc data for the corresponding CustomerDemographic instance.
    public string CustomerDesc { get; set; }
    
}

/// <summary>
/// This class holds data for Category elements.
/// </summary>
public class Category
{
    // Provide access to Picture data for the corresponding Category instance.
    public string Picture { get; set; }
    
    // Provide access to CategoryID data for the corresponding Category instance.
    public int CategoryID { get; set; }
    
    // Provide access to CategoryName data for the corresponding Category instance.
    public string CategoryName { get; set; }
    
    // Provide access to Description data for the corresponding Category instance.
    public string Description { get; set; }
    
}

/// <summary>
/// This class holds data for Customer elements.
/// </summary>
public class Customer
{
    // Provide access to CustomerID data for the corresponding Customer instance.
    public string CustomerID { get; set; }
    
    // Provide access to CompanyName data for the corresponding Customer instance.
    public string CompanyName { get; set; }
    
    // Provide access to ContactName data for the corresponding Customer instance.
    public string ContactName { get; set; }
    
    .
    .
    .
    
}

.
.
.

/// <summary>
/// This class holds data for EmployeeTerritory elements.
/// </summary>
public class EmployeeTerritory
{
    // Provide access to EmployeeID data for the corresponding EmployeeTerritory instance.
    public int EmployeeID { get; set; }
    
    // Provide access to TerritoryID data for the corresponding EmployeeTerritory instance.
    public string TerritoryID { get; set; }
    
    // Provide reference to corresponding Employee instance.
    public Employee Employee { get; set; }
    
    // Provide reference to corresponding Territory instance.
    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):

Image 15

Below is the updated set of C# classes with the ignored CustomerDemographic and CustomerCustomerDemo classes removed.  (Mo+ template in example download is called ClassExceptions):

C#
/// <summary>
/// This class holds data for Category elements.
/// </summary>
public class Category
{
    // Provide access to Picture data for the corresponding Category instance.
    public string Picture { get; set; }
    
    // Provide access to CategoryID data for the corresponding Category instance.
    public int CategoryID { get; set; }
    
    // Provide access to CategoryName data for the corresponding Category instance.
    public string CategoryName { get; set; }
    
    // Provide access to Description data for the corresponding Category instance.
    public string Description { get; set; }
    
}

/// <summary>
/// This class holds data for Customer elements.
/// </summary>
public class Customer
{
    // Provide access to CustomerID data for the corresponding Customer instance.
    public string CustomerID { get; set; }
    
    // Provide access to CompanyName data for the corresponding Customer instance.
    public string CompanyName { get; set; }
    
    // Provide access to ContactName data for the corresponding Customer instance.
    public string ContactName { get; set; }
    
    .
    .
    .
    
}

.
.
.

/// <summary>
/// This class holds data for EmployeeTerritory elements.
/// </summary>
public class EmployeeTerritory
{
    // Provide access to EmployeeID data for the corresponding EmployeeTerritory instance.
    public int EmployeeID { get; set; }
    
    // Provide access to TerritoryID data for the corresponding EmployeeTerritory instance.
    public string TerritoryID { get; set; }
    
    // Provide reference to corresponding Employee instance.
    public Employee Employee { get; set; }
    
    // Provide reference to corresponding Territory instance.
    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):

Image 16

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.):

C#
/// <summary>
/// This class holds data for Category elements.
/// </summary>
public class Category
{
    // Provide access to Picture data for the corresponding Category instance.
    private string picture
    public string Picture
    {
        get
        {
            #region protected
            // this is a customization
            #endregion protected
            return picture;
        }
        set
        {
            picture = value;
            #region protected
            // this is another customization
            #endregion protected
        }
    }
    
    // Provide access to CategoryID data for the corresponding Category instance.
    public int CategoryID { get; set; }
    
    // Provide access to CategoryName data for the corresponding Category instance.
    public string CategoryName { get; set; }
    
    // Provide access to Description data for the corresponding Category instance.
    public string Description { get; set; }
    
}

/// <summary>
/// This class holds data for Customer elements.
/// </summary>
public class Customer
{
    // Provide access to CustomerID data for the corresponding Customer instance.
    public string CustomerID { get; set; }
    
    // Provide access to CompanyName data for the corresponding Customer instance.
    public string CompanyName { get; set; }
    
    .
    .
    .
    
}

.
.
.

/// <summary>
/// This class holds data for EmployeeTerritory elements.
/// </summary>
public class EmployeeTerritory
{
    // Provide access to EmployeeID data for the corresponding EmployeeTerritory instance.
    public int EmployeeID { get; set; }
    
    // Provide access to TerritoryID data for the corresponding EmployeeTerritory instance.
    public string TerritoryID { get; set; }
    
    // Provide reference to corresponding Employee instance.
    public Employee Employee { get; set; }
    
    // Provide reference to corresponding Territory instance.
    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!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)