pmMDA.NET is developed using the coding convention from bbv. The generated source code also fullfill these conventions. TODO: link to convention allowed?
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 are not specified in the bbv coding guidelines.
In pmMDA.NET Interfaces names starts with an I (.NET standard).
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.
// ... public class MyDataObject implements DataObject { // ... private Timestamp timestamp; public Timestamp getTimestamp() return timestamp; } public void setTimestamp(Timestamp timestamp) { this.timestamp = timestamp; } // ... }
MyDataObject myDataObject = new MyDataObject(); Timestamp timestamp = myDataObject.getTimestamp();
// ... public class MyDataObject : IDataObject { // ... private DateTime m_timestamp; public DateTime Timestamp { get { return m_timestamp; } set { m_timestamp = value; } } // ... }
MyDataObject myDataObject = new MyDataObject(); DateTime timestamp = myDataObject.Timestamp;
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.
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.
This package is a copy from the java-pmMDA framework.
Differences between java pmMDA and pmMDA.NET:
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
.
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.
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
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.
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 ( PropertyName
Changed
and PropertyName
Changing.
There is an example at the end of this page.
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.
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. }
*/
Descriptions for the classes, interfaces and types can be found in the API.
Contains the classes used to persist data objects and reference codes.
This package is a copy from the java-pmMDA framework.
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 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.
.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.
NHibernate has a built-in timestamp feature. Unfortunately pmMDA.NET cannot use this feature.
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.
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.
Descriptions for the classes, interfaces and types can be found in the API.
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.
This package is a copy from the java-pmMDA framework.
Descriptions for the classes, interfaces and types can be found in the API.
The application namespace contains the base classes for all applications and their components which use the pmMDA framework.
This package is a copy from the java-pmMDA framework.
Descriptions for the classes, interfaces and types can be found in the API.
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
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.