Friday, 15 June 2007

Most software projects start with an existing database.  It's not often that you get the chance to start from scratch and design the database the way you like it.  Now, creating Genome mappings for an existing database is a tedious job, but thankfully we have the Database Reverse Engineering Wizard for that.  So let's start Visual Studio 2005, and create a new Database Reverse Engineering project.

Genome will start a wizard.  Connect to Northwind, select all tables, accept the names for the projects or choose your own, change any options if you like (I opted to have Genome create default constructors) and click finish.  Genome will now generate two projects for you, one with classes for your domain model, and one for the mappings of those classes to database tables.

Let's have a look at some of the class file that the wizard generated for you. Open the Order.cs (or Order.vb if you selected VB.NET as your language of choice).

    1 using System;

    2 using TechTalk.Genome;

    3 using TechTalk.Genome.Mapping;

    4 using System.ComponentModel;

    5 

    6 namespace Genome.DataDomain

    7 {

    8     [TypeConverter(typeof(ExpandableObjectConverter))]

    9     public abstract class Order : Persistent

   10     {

   11         #region Primary Keys

   12 

   13         public abstract int OrderId { get; }

   14 

   15         protected Order()

   16         {

   17         }

   18 

   19         #endregion

   20 

   21         #region Scalar Fields

   22 

   23         public abstract Nullable<DateTime> OrderDate { get; set; }

   24         public abstract Nullable<DateTime> RequiredDate { get; set; }

   25         public abstract Nullable<DateTime> ShippedDate { get; set; }

   26         public abstract Nullable<decimal> Freight { get; set; }

   27         public abstract string ShipName { get; set; }

   28         public abstract string ShipAddress { get; set; }

   29         public abstract string ShipCity { get; set; }

   30         public abstract string ShipRegion { get; set; }

   31         public abstract string ShipPostalCode { get; set; }

   32         public abstract string ShipCountry { get; set; }

   33 

   34         #endregion

   35 

   36         #region Reference Fields

   37 

   38         public abstract Customer Customer { get; set; }

   39         public abstract Employee Employee { get; set; }

   40         public abstract Shipper ShipVia { get; set; }

   41 

   42         #endregion

   43 

   44         #region One To Many Associations

   45 

   46         public abstract Collection<OrderDetail> OrderDetails

   47         {

   48             get;

   49         }

   50 

   51         #endregion

   52 

   53         #region Many To Many Associations

   54 

   55         public abstract Collection<Product> Products

   56         {

   57             get;

   58         }

   59 

   60         #endregion

   61     }

   62 }

The file starts out with a couple of using declaration that refence the Genome namespaces. The Order class is annotated with the TypeConverter attribute, which is useful to display Genome objects in a property grid.  The first member we encounter is a property for the primary key of the Order entity, in this case a simple integer.  There's also the default constructor, which is protected because we are dealing with an abstract class. Then come a number of simple properties, nothing exciting.  After that it gets more interesting.

The Orders table has several foreign key contraints.  Those foreign keys are represented by references to related objects.  For example, the foreign key to the Employees table as mapped by a property of type Employee.  We have the other direction as well: the OrderDetails table has a foreign key to the Orders table.  This results in the Order class having a collection of OrderDetail objects.  If you take a look at the OrderDetail class, you will find it has a property of type Order for its side of the relation.

Lastly we have an m-p relation between the Orders and the Products tables, with the OrderDetails table as connection table.  Genome creates a collection of Product objects in the Order class, and a collection of Order object in the Product class.

By this time, you are probably wondering why the classes and all those properties are abstract. The reason becomes clear when we use Reflector to have a look at the assembly compiled by Genome.

For every class generated by the Database Reverse Engineering wizard, there are two classes in this assembly: one in a namespace starting with GenomeContextBoundProxy and one in a namespace starting with GenomeContextUnboundProxy.  The Genome runtime will use one or the other depending on the Genome Context. The distinction between the two kinds of proxies isn't that important, though. What is important is the fact that Genome uses the proxy design pattern. This all happens behind the scenes however, so as an application developer you will only deal directly with the abstract classes.

In the next installment, I'll use the Genome starter kit to create a web application that uses the two projects we just generated.

Posted by Dirk

Technorati Tags: object relational, getting started