pmMDA.NET Design

Coding guidelines

pmMDA.NET is developed using the coding convention from bbv. The generated source code also fullfill these conventions. TODO: link to convention allowed?

pmMDA.NET coding guidelines

Class variables

As defined in the bbv code guidelines, member variables have the prefix m_. The reason therefore is that the properties would otherwise have the same name as the member variables if the used language is case insensitive (like VB.NET).
And because pmMDA is CLS compatible, and therefore can be accessed from VB.NET, the class variables have the prefix m_.
Note that all class variables, not only the value holders for properties, have the prefix m_ to avoid complex coding conventions.

The users of the pmMDA.NET framework will not notice the m_ prefix because all class variables are private. But for developers of the pmMDA framework this fact is important.

Interface names

Interface names are not specified in the bbv coding guidelines.
In pmMDA.NET Interfaces names starts with an I (.NET standard).

Properties

In Java properties are simulated by get and set methods. The .NET Framework has a different implementation of the property concept. The properties in .NET are written with a special language construct (i.e. property in C#) and are accessed like normal variables.

.NET developers are used to the .NET property concept. Thus it makes sense that all get or set methods, which represents properties in the java pmMDA framework, are converted to .NET properties for the pmMDA.NET framework. The property name is the same as in the java pmMDA framework except that the get and set prefix is removed. For someone with excellent knowledge of the java pmMDA framework it is very easy to use the pmMDA.NET framework because he just has to omit the get or set prefix.

Another advantage of using .NET properties is that the data binding feature of the .NET framework can be used. TODO: stimmt so nicht ;)

This coding convention is used in the pmMDA.NET framework as well as in the .NET Cartridges of the pmMDA explorer.

Java example
Defining a property
// ...
public class MyDataObject implements DataObject {
   // ...
   private Timestamp timestamp;

   public Timestamp getTimestamp()
      return timestamp;
   }

   public void setTimestamp(Timestamp timestamp) {
      this.timestamp = timestamp;
   }
   // ...
}
Accessing the property
MyDataObject myDataObject = new MyDataObject();
Timestamp timestamp = myDataObject.getTimestamp();
C# example
Defining a property
// ...
public class MyDataObject : IDataObject {
   // ...
   private DateTime m_timestamp;

   public DateTime Timestamp {
      get {
         return m_timestamp;
      }
      set {
         m_timestamp = value;
      }
   }
   // ...
}
Accessing the property
MyDataObject myDataObject = new MyDataObject();
DateTime timestamp = myDataObject.Timestamp;

pmMDA.NET Package Diagram

Introduction

The pmMDA.NET framework is a set of classes which allows the generated artefacts to be run on the .NET framework. The .NET framework is similar to the java pmMDA framework so that developers don't need to learn a new framework when changing the platform in pmMDA.

pmMda.NET package diagram

PmMda.Net.Dog

Introduction

Modern client-server applications manipulate complex graphs of data objects. For example a contract with its positions and optional amendments is represented as a hierarchy of data information. These graphs are transferred from and to the client application. The user views data edits it and commits the changes to the database through server functions. The patterns commonly found in the literature describe thoroughly how to implement simple data transfer objects DTO, but ignore the complexity of how graphs of objects should efficiently be transmitted between server and client components. The intended audience is software developers interested in using DOG or implementing their own variant.

Design decisions

This package is a copy from the java-pmMDA framework.
Differences between java pmMDA and pmMDA.NET:

Property events

Properties of data objects can raise two events. The changed event is raised if the tagged value .net-dog-change-event is set to true. The vetoable event is raised if the tagged value .net-dog-veto-event is set to true.

Event mechanism

Java-pmMDA uses the PropertyChangeSupport for the property events.
pmMDA.NET uses the event concept built-in the .NET framework to define the property events.

Property changed events

pmMDA.NET uses the .NET naming convention for bindable properties. The events are defined using the PropertyChangedEventHandler. The argument of the events is of type PropertyChangedEventArgs.
TODO: data binding

Vetoable change events

The vetoable events have the suffix "Changing" and are defined using the PropertyChangingEventHandler. The argument of the events is of type PropertyChangingEventArgs. To cancel the change of the property, set the Cancel property to false. In java pmMDA a PropertyVetoException would be thrown in that case.

Connect to events

In java-pmMDA there are two methods (addPropertyChangeListener and addVetoableChangeListener) which allow to connect to every property event. In pmMDA.NET there are (at maximum) two events for each Property ( PropertyNameChanged and PropertyNameChanging.
There is an example at the end of this page.

Raising the events

In the .NET framework it is a common behaviour to raise the events from a separate method. This method name consists of the prefix "On" followed by the event name. It takes the event arguments as parameters and is protected and virtual.
This pattern allows derived classes to be notified about the events by overriding the event method witout having to register for events. Also the event methods allow derived classes to raise the events.

pmMDA.NET defines the event methods and calls them during the change of properties instead of raising the events directly.

Code example (C#)

Event definition

// ...
public class MyDataObject : IDataObject {
   private string m_name;
   // ...
   public event PropertyChangedEventHandler NameChanged;
   public event PropertyChangingEventHandler NameChanging;
   // ...
   public string Name {
      get {
         return m_name;
      }
      set {
         PropertyChangingEventArgs e = new PropertyChangingEventArgs(this, "Name", m_name}, value);
         OnNameChanging(e);
         if (e.Cancel) {
            return;
         }
         m_name = value;
         Modified = true;
         OnNameChanged(new PropertyChangedEventArgs(this, "Name"));
      }
   }
   // ...
   protected virtual void OnNameChanged(PropertyChangedEventArgs e) {
      if (NameChanged != null) {
         NameChanged(this, e);
      }
   }

   protected virtual void OnNameChanging(PropertyChangingEventArgs e) {
      if (NameChanging != null) {
         NameChanging(this, e);
      }
   }
// ...
}

Connect to events

void SomeMethod() {
   MyDataObject myDataObject = new MyDataObject();
   myDataObject.NameChanged += new PropertyChangedEventHandler(myDataObject_NameChanged);
   myDataObject.NameChanging += new PropertyChangingEventHandler(myDataObject_NameChanging);
   // for other properties
   // myDataObject.PasswordChanged += new PropertyChangedEventHandler(myDataObject_PasswordChanged);
   // myDataObject.PasswordChanging += new PropertyChangingEventHandler(myDataObject_PasswordChanging);
}

private void myDataObject_NameChanged(object sender, PropertyChangedEventArgs e) {
   // name changed event is raised in this method
}

private void myDataObject_NameChanging(object sender, PropertyChangingEventArgs e) {
   // name changing event is raised in this method
   // e.Cancel = true; // to abort the change of the property.
}

/* for password property
private void myDataObject_PasswordChanged(object sender, PropertyChangedEventArgs e) {
   // password changed event is raised in this method
}

private void myDataObject_PasswordChanging(object sender, PropertyChangingEventArgs e) {
   // password changing event is raised in this method
   // e.Cancel = true; // to abort the change of the property.
}
*/

Indexed properties event: TODO:

Design diagram

Descriptions for the classes, interfaces and types can be found in the API.

PmMDA.NET.DOG.Persistence

Introduction

Contains the classes used to persist data objects and reference codes.

Design decisions

This package is a copy from the java-pmMDA framework.

OR mapper

Introduction

An OR mapper mapps the object orientated objects of programming languages to relational databases.

Currently pmMDA.NET supports only the OR mapper NHibernate. It is planned to support other OR mapping frameworks such as ObjectSpaces in feature.

NHibernate

NHibernate is a port of the java project Hibernate. Although there is a port of OJB for .NET ( OJB-NET) we think that NHibernate is the better choice. See the document "pmMDA - OR mapper" for more information.

Assembly information in NHibernate repository

.NET reflection uses the method Type.GetType to get the Type for a qualified name. NHibernate uses this feature to get the Types of the data objects specified in the *.hbm.xml files (NHibernate config files). The type names need to be fully qualified as described in the MSDN article Specifying Fully Qualified Type Names. This means that pmMDA.NET needs to know the assembly name to generate the repository files (*.hbm.xml) used by NHibernate.

pmMDA.NET generates the NHibernate configuration files using a fully qualified name (namespace.class, assembly) for the data objects to map them to their database table. Therefore pmMDA.NET needs to know the assembly names where the data objects will be compiled to.
But because pmMDA doesn't compile the generated artefacts, it doesn't know the assembly names where the data objects are located after the compilation.

To solve that problem pmMDA.NET defines a tagged value ".net-nhibernate-assembly" which can be specified in the packages which contain data objects. The value of this tagged value is used to generate the NHibernate configuration files. For a successful compilation and execution of the application generated by pmMDA.NET, the data objects must be placed in that specified assembly.

Timestamps
Built-in timestamp feature

NHibernate has a built-in timestamp feature. Unfortunately pmMDA.NET cannot use this feature.

Problem description

If we have an object "A" which references 4 objects of type "B" within the indexed property "bs". TODO: class & | object diagram &| relational diagram
Assume this objects where first loaded from the database. Now we want to delete the "A" object and 3 of the 4 "B" objects in the same transaction. Untill we commit the transaction NHibernate will collect the Sql statements to execute. On commit the statements are ordered and executed. Deleting the object "A" and the 3 "B" object will result in the following Sql statements:

UPDATE BTable SET A_B_FK=NULL WHERE A_B_FK=A.Id
DELETE * FROM BTable WHERE ID=B1.Id AND TS=B1.Timestamp
DELETE * FROM BTable WHERE ID=B2.Id AND TS=B2.Timestamp
DELETE * FROM BTable WHERE ID=B3.Id AND TS=B3.Timestamp
DELETE * FORM ATable WHERE ID=A.ID AND TS=A.Timestamp

Sadly the update statement will be executed before the delete statements (not configurable or changable).
The update statements will modify the TS column of all "B" objects in the database. When the first delete statement is executed the column with the timestamp B1.Timestamp can not be found, because it has changed while the execution of the update statement.

Solution

pmMDA doesn't use the NHibernate timestamp feature. It will handle the timestamp rows as NHibernate properties. Setting the update and insert attributes to false will prevent the timestamp to be written within the INSERT and UPDATE statements. The database will set the timestamp column automatically.
The property type "timestamp" ensures that NHibernate converts the database timestamp to a .NET DateTime value.

Because in our solution NHibernate doesn't add the timestamp to the where clause of the Sql statements, the optimistic concurrency must be implemented manually. The Persistence handler (see the PersistenceHandler class in the API) checks the timestamp before the data objects are updated or deleted. If the timestamp is not equal to the current database timestamp the data object has been modified by another trannsaction. In that case an exception is thrown.

Design diagram

Descriptions for the classes, interfaces and types can be found in the API.

PmMDA.NET.DOG.Reference

Introduction

A reference code is an enumeration of values defining a domain relevant type and its legal values. For example the set of currencies defined in the related ISO standard is a reference code. Each code is identified by the type it belongs to - represented as a C# class derived from IReferenceCode - and a unique code identifier. Reference codes can have a hierarchical structure. For example the department structure of a worldwide company can be represented through a hierarchical reference code.
The framework knows the concept of reference code and uses the reference code manager (ReferenceCodeMgr) to access values of codes. The implementation of the framework never stores reference code objects or send them over the wire. Only the identifier of the code is stored or transmitted. Reference code objects are always transient ones. The mapping to the type is done implicitly.
The database definition connects the identifier of the code to the reference code table. Therefore persistent properties can only contain persistent reference codes. Technically, codes are mapped to 1-0..1 or 1-1 relationships.
The transformer factory knows the dependency between identifier and type. The name of the identifier is hard coded in the transformation routines. This approach is congruent with the concept of a reference code being a typed business enumeration.
Transient reference codes are build in the application logic and are not part of the data object graph framework.
The framework provides services to transfer reference codes from the server to clients. Incremental updates are available to minimize network overhead.

Design decisions

This package is a copy from the java-pmMDA framework.

Design diagram

Descriptions for the classes, interfaces and types can be found in the API.

PmMDA.NET.Application

Introduction

The application namespace contains the base classes for all applications and their components which use the pmMDA framework.

Design decisions

This package is a copy from the java-pmMDA framework.

Design diagram

Descriptions for the classes, interfaces and types can be found in the API.

Diverse

Extension to pmMDA explorer

Velocity templates

The velocity templates used to generate the pmMDA.NET artefacts need a second macro library. This library must be included in the configuration file "pmmda.properties":

velocimacro.library=mda-macros.vm,net-macros.vm

Helper classes

The pmMDA.NET cartridges use a helper class named NetCartridgeHelper to convert java specific constructs to C#. The NetCartridgeHelper can also get some information out of the pmMDA meta model which is not directly accessible through the meta model classes (i.e. getting the data objects which are derived from a specified data object).
It's planned to move the features of the helper class directly to the pmMDA model library if they remain stable.