Saturday, March 03, 2007

Getting VOA to run - Persisting a simple object

After having set up VOA on your PC, you sure want to try persisting an object. So what´s the quickest way to reach this goal?

Step 1: Create a VS2005 solution+project to put your code into. Either use a console application project or a library project like I did (for details on my code organization see below).

Step 2: "Enable" your project by stepping through the VOA wizard at OpenAccess|Enable Project in the VS2005 menu.

The wizard will add some configuration information to the App.Config of the project and add some project properties.

You can leave most settings on the wizard pages at their defaults. However, if you´re using SQL Server 2005 Express as your database, you need to change the server name to .\SQLEXPRESS. Also you should check, if your database can be reached via TCP. For SQL Express you can use the Configuration Manager.

 

Due to a recent re-installation of VS2005 it happened to me, that neither the Named Pipes nor TCP/IP protocols were enabled, which lead to a very annoying error message when compiling my sample project. So be sure to use the right server name and make it available.

Why this enabling of a project? Well, VOA is not just a library you link to and use a couple of classes from. In order to make object persistence as unobtrusive as possible for you, it needs to weave some magic in the background. That´s what the project properties are about. But more of that later.

For now let me just say: You won´t have to run through this enabling procedure for every project you´re using persistent objects in.

Step 3: The wizard of course also has some more tangible effects. If takes off you the burden to create a XML config file and reference the VOA assemblies OpenAccess.20 and vjslib. If you now guess, VOA has something to do with J#, you´re right. VOA internally is partly based on Java which has been ported to the .NET world. Other parts of it have been written in C#. Is this Java background good or bad? I´d say, both. It´s good because it´s the reason why VOA had been one of the first professional O/R mappers for .NET; it simply had existed before in the Java world and was able to accumulate quite some experience. So when it came to .NET it was not a 1.0 version. But the Java legacy also has a drawback: Database access is not based on ADO.NET Managed Providers but rather is still tied to JDBC. This makes it harder for Vanatec to make VOA compatible with a lot of database products. They can´t just internally use the OleDb Managed Provider or even use the new ADO.NET 2.0 generic provider model to access Jet Engine MDB-databases or coming with their own Managed Providers. However, VOA supports SQL Server, Oracle, and MySQL which seem to be the most important databases for a large number of .NET developers.

Now, that the wizard has done its work, add your own code. For example you could store some personal information on people you know, e.g. their first name. For that define a class like this:

   32 [OpenAccess.Persistent]

   33 public class Person

   34 {

   35     public string firstname;

   36 }

 
In order to later on easily persist objects of this class you only have annotate it with the [OpenAccess.Persistent] attribute. The rest is VOA magic ;-)

Then use the following code to actually create and store an instance of your Person class: 

   16 OpenAccess.IObjectScope os;

   17 os = OpenAccess.Database.Get("DatabaseConnection1").GetObjectScope();

   18 os.Transaction.Begin();

   19 

   20 Person p;

   21 p = new Person();

   22 p.firstname = "John";

   23 

   24 os.Add(p);

   25 

   26 os.Transaction.Commit();

   27 os.Dispose();


For now, think of the IObjectScope "thing" as a database connection. So you create/open a "connection" using the settings from the App.Config and start a transaction on that connection. Then you create an object of the persistent class and add it to the "connection". At the end, just commit the transaction and the object will be stored in the database.

Try it now. You´ll it works. Here´s what my database looked like afterwards:

 
 Which database, you might ask now? Well, the database whose name you provided to the wizard. If it did not exist before, VOA creates it during compilation of your code. Also VOA creates tables to store you´re persistent objects in. And if you change a persistent class´s definition, VOA synchronizes the database schema with it.

This is called Forward Mapping. It means, the database schema is automatically derived from your persistent classes. As long as you use forward mapping - which is the default - you don´t need to be concerned much with any database schema. As an object oriented programmer you think in objects/classes and let VOA do the rest, i.e. the mapping to a database schema. But more of that later in some future article.

For now let´s be content with the result of our first experiment: Object persistence is easy. Create a project, annotate any class whose instances you want to persist with an attribute, open a VOA "connection" to the database, start a transaction, add objects to the "connection", and commit the transaction. That´s it. Just a couple of lines of code. Think of how much more effort you would have had to invest to do the same with ADO.NET! You´d also need to use a connection, then set up a command, then check if the data should be updated in the database or added... All very tedious work, and many, many lines of code. No so, though, with an O/R mapper like OpenAccess.

But you´re right: This was just a trivial example. What about more complex scenarios? Well, I´ll get to them during my exploration. And I´m as interested as you to see, how VOA will live up to them.

My sample scenario environment 

Before I close a quick word about how I organize my code. Since I provide it for you to download, you should know how to find your way around.

I created a Samples folder to put all my code into I write for this blog. Within this root folder I created a libs subfolder for any third party assemblies I might need. At this time that´s just the NUnit libaries, since I intend to set up as many samples as unit tests as possible, so I can re-run them easily and automatically at any time to check, if they still work, e.g. after installing a VOA update. The .NET Fx assemblies and VOA´s assemblies I leave in their original places.

All the VS2005 solution I am going to create will also be placed in the Samples folder. The above sample you find in solution VOASamples01 in project SimpleWithGlobalDB. This project is not a console application, but a library. It will be hosted and run by a NUnit test framework. I use TestRunner from Mailframe.

For that to work I don´t use a Main() method like in a console application to start my code, but a NUnit Test method sitting in a NUnit TestFixture class.

    1 using System;

    2 using System.Collections.Generic;

    3 using System.Text;

    4 

    5 using NUnit.Framework;

    6 

    7 namespace SimpleWithGlobalDB

    8 {

    9 

   10     [TestFixture]

   11     public class Main

   12     {

   13         [Test]

   14         public void Run()

   15         {


This might need some getting used to it, but in the end it´s as simple as writing a console application - but has the advantage of being able to let many such samples run automatically and check their results.

 
 
Technorati tags:

4 comments:

Anonymous said...

First thing i always do when evaluate an ORM tool is see how easy it handles many-to-many relationships... seems like getting it "right" is one of the most challenging aspects for any ORM product.

Ralf Westphal - One Man Think Tank said...

@anonym: Thx for the suggestion. I sure will look into how VOA handles n:m relationships. But I´ll not jump to that. Rather I want to take smaller steps into the O/R mapping territory.

Claudio Greuter said...

Thanks for the examples and intros in these blogs, the really helped me with the first steps while evaluating VOA.

I stumbled over an issue though, and would like to ask you for your opinion: I found it difficult to evolve the model: I tried to rename a variable of a persistent object to check what happens to existing data on the database. Outcome: the "old" column has been deleted and a new one has been created (instead of renaming). I Think this makes to harder to perform refactorings on the code. How would you deal with it?

Ralf Westphal - One Man Think Tank said...

@Claudio: Schema evolution sure is an issue. I´ll tackle it in a future posting.

However, what you describe should not happen: If you use forward mapping and rename a field, what VOA should do is: create a new column in the table with the new fieldname and leave the column with the previous fieldname untouched. So the old values should not get deleted, but are simply not accessible through the persistent class anymore.

-Ralf