I just got out of this session and am writing this from the bus on the way back to my hotel. From there we are off to Universal Studios for the attendee party. They've rented out the entire place for just us! Kick ass.
If you've read my blog for long, you've probably heard me rave about code generation tools like CodeSmith and LLBLGen. I've written a number of Object Relational Mapper (ORM) tes in CodeSmith and I've demoed LLBLGenPro. Both techniques work well, but I've always wanted something built into the framework. The ones I wrote were specifically for my needs and didn't support things like relationships, lazy loading of child relationships, etc. LLBLGen supports some of that, maybe all, but it is still essentially a code generator.
I've been hearing about ObjectSpaces for a while now but it has been very hard to get any information about it. And with all the hype about the other Whidbey and Longhorn technologies, it seemed to be ignored by the community.
ObjectSpaces is three things:
1. System.Data.ObjectSpaces is the namespace containing the core ORM subsystems in Whidbey
2. Microsoft.Data.ObjectSpaces (or something like that) contains utilites for generating databases from object graphs and vice versa
3. VS.NET (Whidbey) will have a very cool editor for mapping table and columns to objects and fields.
This stuff appears to be exactly wat I was hoping for. I tried my best to copy the code from the demos below, and for this kind of this the code is the best way to see what is going on. I cannot guarantee that this code is correct, and it certainly will not compile, as I was typing it in on the fly as the presenter switched between slides and code. But it is close enough to give you an idea of what I was seeing. Unfortunately I didn't catch all of the code for ObjectSpaces -> ADO.NET interop (case 5), but I'm sure that will be pretty straightforward. This is the Good Stuff.
Look in the switch statement to see how database initialization, reading and then updating work. This stuff is VERY cool and is going to save us business app developers TONS of time and code.
Enjoy!
using Microsoft.Data.ObjectSpaces;
using System;
using System.Collections;
using System.Data.ObjectSpaces
public class Continent
{
public Continent(string name, int area)
{
Name = name;
Area = area;
}
public string Name;
public int Area;
public ArrayList Countries = new ArrayList();
private Continent();
}
public class ContinentDelayLoad
{
public Continent(string name, int area)
{
Name = name;
Area = area;
}
public string Name;
public int Area;
public ObjectList Countries = new ObjectList();
private Continent();
}
public class Country
{
public Country( string Name, int pop, Continent cont ) { ... }
public string Name;
public int Population;
public ArrayList Cities = new ArrayList()l
public Continent Continent;
private Country() {};
}
public class City
{
public City() string name, int numberOfCats, Country myCountry )
{
_Name = name;
NumberOfCats = numberOfCats;
Country = myCountr;
}
private string _Name;
public string Name
{
get { return _Name; }
set { _name = value; }
}
public int NumberOfCats;
public Country Country;
private City() {}
}
public class WorldDriver
{
static void InitializeDatabase()
{
Continent asia = new Continent("Asia", 17110 );
...
Country china = new Country( "usa", 111, asia );
...
City beijing = new City( "Beijing", 1112, china );
...
ObjectPersisitence op = new ObjectPersistence( "Data Source=(local); Integrated Security=true;", "World" );
Print("Persisting Asia");
op.Persist( asia );
op.Persist( asia.COuntries );
foreach( Country c in asia.Countries )
{
op.Persist( c.Cities );
}
}
static void Main( int argc, char[] argv )
{
int whichDemo = Int32.Parse( argv[1] );
switch( whichDemo )
{
case 1:
InitializeDatabase();
break;
case 2:
os = new ObjectSpace("World.msd.xml", cn);
ObjectSet oset = os.GetObjectSet( typeof(City), "", "" );
Print( oset );
break;
case 3:
os = new ObjectSpace("World.msd.xml", cn);
City gt = (City) os.GetObject( typeof(City), "Name='Absiola');
Print("Got it");
gt.NumberOfCats = new Random().Next();
try
{
os.PersistChanges(gt);
}
catch( Exception e )
{
os.Rollback();
}
break;
case 4:
os = new ObjectSpace("World.msd.xml", cn);
os.BeginTransaction( IsolationLevel.RepeatableRead);
City gt = (City) os.GetObject( typeof(City), "Name='Absiola');
Print("Got it");
gt.NumberOfCats = new Random().Next();
try
{
os.PersistChanges(gt);
os.Commit();
}
catch( Exception e )
{
os.Rollback();
}
break;
case 5:
string cs1 = "DataSource=(local);Integrated security=true;...";
string query = "select top 3 * from coutnry";
SqlCommand cmd = new SqlCommand( query, new SqlCOnnection(cs1) );
SqlDataReader r = cmd.ExecuteReader();
MappingSchema map = new MappingSchema("Woeld.msd.xml");
DbObjectReader reader = new DbObjectReader( r, typeof( ) );
break;
}
}
static void Print( string s ) ...
static void Print( IList c ) ...
static void PrintContinents( IEnumerable e ) ...
static void PrintCountries( IEnumerable e ) ...
static void PrintCities( IEnumerable e ) ...
}