Object-Oriented Data Programming: C# Meets Cachéby Jesse Liberty
Virtually every meaningful commercial ASP.NET or Windows application stores and retrieves data. Most programmers use a relational database for data storage, and Microsoft has gone to great lengths to create a set of classes that mediate between the object-oriented viewpoint of C# and VB 2005 programming on the one hand, and the tables/rows/columns perspective of relational databases on the other (ADO.NET).
There are, however, other ways to store your objects, one of which is to use an object-oriented database. The idea would be to create objects, and then just store them and retrieve them without thinking at all about tables/rows/columns or even relations!
Now, with that in the back of your mind, consider this problem: many hospitals and other institutions have been using a non-relational database called MUMPS (Massachusetts General Hospital Utility Multi-Purpose System) for the past 40 years (!). They are deeply invested in this technology, and, hey! it works. In 1994 InterSystems bought up various versions of MUMPS and in 1997 they released Caché, using the MUMPS storage engine and language, but with object-oriented services on top. They realized that these institutions do not want to walk away from their data, but they do want to use modern languages, such as Java and C# to create the front end to their new applications.
MUMPS and C#
Flash forward to today. I was asked by the Dana-Farber Cancer Institute (Partners Health Care) in the Boston area to help a group of in-house developers create a new system for their pharmacy that will use MUMPS Globals (the underlying storage) but with a .NET 2005 Windows Forms front end.
Originally I thought, "OK, I'll build the front end, and someone else will worry about this weird non-relational (InterSystems calls it "post-relational") database. But it turns out that you can create objects in Caché (and let it write the globals automagically), and then use their wizard to import Caché objects into (proxy) C# classes.
This was too good not to write about, because it illustrates so many interesting ideas:
- How do you revitalize 40-year-old data technology in the world of objects?
- What is .NET programming with an object-oriented database like?
- How do proxy objects allow C# programmers to thinks they are programming against an object that is really just a set of DB calls?
Actually, there are many other nifty lessons to be learned along the way, but the best way to see them is to create an application. We're going to create a very simple application, and walk through all the steps, which include:
- Design the objects without regard to implementation
- Design the Caché objects that correspond to our ideal objects
- Implement the Caché objects
- Design a C# project that thinks about persistence in terms of objects rather than data sets and tables
- Import the Caché objects into C# using the Caché Wizard
- Interact with the objects in C#. Create new objects, update existing objects, and store objects
Building a Demo Application
To illustrate how this all works we want to build a very simple application that lets you pick from a list of patients and see what medications they take, in what dosage, and by what route (by mouth, IV, etc.).
To implement this, let's think about what objects we'll need, first without regard to implementation details.
Clearly we need a
Patient class, and we can imagine that the
Patient class inherits from
Person providing the name, address, phone numbers, etc. and
Patient providing the patient ID, list of prescriptions, list of doctors, list of disorders, etc.
Let's think about
Prescriptions. To start, there is a
Medication (e.g., Lexapro), a
Dosage (e.g., 20mg), and a
Route (e.g., by mouth). There is also a prescribing doctor, a prescription date, the date the prescription was dispensed, how many were ordered, how many were actually delivered, and so forth.
How do we handle the
Medication? Many medicines come only
in certain dosages, and some are safe only via certain routes (never give yourself
an intravenous (IV) epinephrine injection). Ahhh, complexity. For the purpose
of this demo, we'll simplify, and create the following truncated classes:
Of course, in a real application, there would be many more fields, and some of the simple fields here would be more complex (for example, the patient's doctor would be of type
Physician which in turn would derive from
Notice that the
Route classes contain only a single member. These classes will be used as lookups, so that we can fill drop-down boxes with legitimate values.
To create even this simple application, we'll need the following forms:
- Creating and Deleting Routes
- Creating and Deleting Medication Names
- Creating, Editing, and Deleting Patients (within which will be a list that allows you to add and delete prescriptions)
- Picking a Patient to review or edit