RM for .NET
Home Up

 

I have implemented RM Relationship Manager for .NET using the Boo language (porting it from Python).  The resulting assembly is usable from C# and other .NET languages.  See C# example below.

Boo is a version of Python blended with C# creating a magnificent hybrid -  to ready my thoughts on Boo click here

 Here are my tips for Developing & Debugging visually in Boo 

Installation

Download the ready to use compiled assembly (includes a sample exe)

To relationship manager in your own projects just add the reference to the assembly RelationshipManager55.dll and create a RM1 instance and then make calls on it using the API below. e.g. R(), NR() etc.  A full example is shown below.

Source code

View the Boo source code of Relationship Manager for .NET online (color coded) on the Boo wiki page.  If you want to compile it yourself then download the entire  SharpDevelop project here.

If you are interested in the .Net 2.0 port of relationship manager, email me.

What is Relationship Manager good for?

> I'd appreciate an 'how to use' example
> to get a quick / better idea on what
> it's useful for when programming

The basic idea with relationship manager is that it is like a
dictionary, which maps relationships between two things, be they object
references or strings or whatever. In my examples I usually use
strings, though object references are commonly used too, in order to
map relationships between object instances.

The benefit over a dictionary is that you can have multiple mappings
e.g.
a -> 1
a -> 2
a -> 3

then you can ask what 'a' points to and get the result
[1, 2, 3]

you can also ask what is pointing to 3, and get the result
 a

One common use of this technology is to do all your wiring between
objects using a relationship manager, thereby saving yourself having to
implement your own one to many lists and having to maintain fiddly
backpointer logic etc. So you still have e.g. an AddOrder(o) method on
your e.g. 'Person' class...its just that you implement the method using
a one line call to the relationship manager - simple!  e.g.

class Person:
    def AddOrder(o):
        RM.addRelationship(self, o, 'personToOrderRelationship')
    def GetOrders():
        return RM.findObjectsPointedToByMe(self,'personToOrderRelationship') 

There is a bit more of a tutorial code sample in the post http://tinyurl.com/9xz5m 

API Documentation

The API of the relationship manager for .NET is the new one described in RM Theory

 Note the .NET assembly only uses the shorthand names e.g. ER() instead of EnforceRelationship().  I'll fix this one day.

Also note that BS(t) is not implemented in the boo port.  This is a temporary omission.  If you need this method urgently, edit RM.boo and add the following to the class RM1:

def BS(toObj, relId):
    # findObjectsPointingToMe(toMe, id, cast)
    return self.rm.FindObjects(null, toObj, relId)

 

Basic API

Returns
Function Name
Short-hand 
void
addRelationship(f, t, id)
R(f,t)
void
removeRelationship(f, t, id)
NR(f,t)
Vector
findObjectsPointedToByMe(f, id)
PS(f)
Vector
findObjectsPointingToMe(t, id)
BS(t)
 

Extra API

Returns
Function Name
Short-hand 
void 
EnforceRelationship(id, cardinality, bidirectionality)
ER(id, c, bi)
Object
findObjectPointedToByMe(fromMe, id, cast)
P(f)
Object
findObjectPointingToMe(toMe, id cast)
B(t)
void
removeAllRelationshipsInvolving(o, id)
NRS(o)

The extra API allows you to enforce relationships e.g.

   ER("xtoy", "onetoone", "directional")

registers the relationship  as being one to many and directional, so that e.g. when you add a second relationship between the same two objects the first relationship is automatically removed - ensuring the relationship is always one to one. Alternatively, you could raise and exception.

The extra API also adds a pair of find methods that only find one object, and cast it to the appropriate type.  This is a commonly used convenience method.

UML class diagram for the .NET relationship manager implementation.

Templates for use

I recommend you look at the templates for what relationship manager API calls to make in order to model any relationship pattern you want.  For example, to implement a one to many relationship between two classes X and Y, you might use the following template:

one to many  
1  -->  *                       directional    
     Plural  API                             No API
  _____________        ______________
 |      X      |      |       Y      |
 |_____________|      |______________|
 |             |      |              |
 |addY(y)      |1    *|              |
 |getAllY()    |----->|              |
 |removeY(y)   |      |              |
 |_____________|      |______________|
picture
class X:
    def __init__(self):        RM.ER("xtoy", "onetomany", "directional")
    def addY(self, y):         RM.R(self, y, "xtoy")
    def getAllY(self):  return RM.PS(self, "xtoy")
    def removeY(self, y):      RM.NR(self, y, "xtoy")
    
class Y:
    pass

 

template

Thus if you have a class called Customer and a class called Order, then the Customer class would correspond to class X and the Order class to class Y.  Your methods might be AddOrder(o) which corresponds in the above example to addY(y).

Its up to you to rename both the class and method names of the template to match your own classes.

A concrete example

Say you want to model a Person class which has one or more Orders.  The Orders class has a backpointer back to the Person owning it.

Instead of hand coding and reinventing techniques for doing all the AddOrder() methods and GetOrders() methods etc. using ArrayLists and whatever, we can do it using the relationship manager object instead, which turns out to be simpler and faster and less error prone. 

The RM (relationship manager) is implemented in this particular example as a static member of the base BO (business object) class.  Thus in this situation all business objects will be using the same relationship manager.

Here is the c# code to implement the above UML:

using System;
using System.Collections;
using RelationshipManager55;

namespace WindowsApplicationUsing_RelationshipManagerDllTest001
{
	/// <summary>
	/// BO is the base Business Object class which holds a single static reference
	/// to a relationship manager. This one relationship manager is
	/// used for managing all the relationships between Business Objects.
	/// </summary>
	public class BO  // Base business object
	{
		static protected RM1 RM = new RM1();
	}

	/// <summary>
	/// Person class points to one or more orders.
	/// Implemented using a relationship manager rather 
	/// than via pointers and arraylists etc.
	/// </summary>
	public class Person : BO
	{
		public string name;

		static Person()
		{
			RM.ER("p->o", "onetomany", "bidirectional");
		}

		public Person(string name)
		{
			this.name = name;
		}
		public override string ToString()
		{
			return "Person: " + this.name;
		}

		public void AddOrder(Order o)
		{
			RM.R(this, o, "p->o");
		}
		public void RemoveOrder(Order o)
		{
			RM.NR(this, o, "p->o");
		}
		public IList GetOrders()
		{
			return RM.PS(this, "p->o");
		}
	}

	/// <summary>
	/// Order class points back to the person holding the order.
	/// Implemented using a relationship manager rather 
             /// than via pointers and arraylists etc.
	/// </summary>
	public class Order : BO
	{
		public string description;

		public Order(string description)
		{
			this.description = description;
		}
		public override string ToString()
		{
			return "Order Description: " + this.description;
		}

		public void SetPerson(Person p)
		{
			RM.R(p, this, "p->o");  // though mapping is bidirectional,
					there is still a primary relationship direction!
 
		}
		public Person GetPerson()
		{
			return (Person) RM.P(this, "p->o");
		}
		public void ClearPerson()
		{
			RM.NR(this, this.GetPerson(), "p->o");
		}
	}

}

Here is the project source code WindowsApplicationUsing RelationshipManagerDllTest001.rar 

Feedback?

Contact abulka@netspace.net.au 

See also

The original design pattern RM Relationship Manager
The latest API and discussion RM Theory.