db4o: Persistent Classes Tips

In the last four posts I’ve mostly talked about db4o itself and how to used it.  All this is actually just the necessary evil for our goal, to persist our data. So here are some very basic tips how to model your persistent classes for db4o (well it applies also to other technologies).

(All posts of this series: the basics, activation, object-identity, transactions, persistent classes, single container concurrency, Queries in Java, C# 2.0, client-server concurrency, transparent persistence, adhoc query tools)

Don’t Go Berserk With Your Data-Model a.k.a KIS

My first advice is extremely general and applies to nearly all engineering areas: Keep It Simple (KIS). Keep your data-model as simple as possible to do the job. Well it’s might fun and challenging to show your great intellect by designing the most awesome data-model ever. However it will almost certainly bite you later when you have to maintain the application.

Why do I tell this here? Well db4o makes it quite easy to just create a ton of classes and store a complex object graph. But only because its easy to store and retrieve objects it doesn’t solve your data-modeling challenges by magic. You still need to evaluate, test and manage your data-model very careful. Otherwise it will end in a mess.

db4o data-model keep it simple

db4o data-model keep it simple

Ok, now to more concrete tips.

Be Careful With Framework Classes

Let’s take a look at this innocent looking example. It’s just a very simple class which holds a color. Since it is a WPF-Application why not using the existing Color-class? Here’s the code:

using System.Windows.Media;

namespace Db4OSeries
{
    public class SimpleObject
    {
        public Color BackGround { get; set; }
    }
}

So you store some colors. It may works fine for a while. However when you take look with the ObjectManager (a tool to view the database) at your database, you notice that there are lots of classes, like Uri, UriParser, Win32.SafeHandles etc. How the hell got those classes into your database? You just stored some SimpleObject-instance with a Color. The answer is within the Color-Class. The Color class may look like it is simple class. However it can hold a reference to a Color-Context, which holds information about how to render colors down to references into the Operation-System. 

So what’s the conclusion? Be VERY, VERY careful when you pull in framework classes. Normally you don’t have any clue what such a class actually stores. That’s information-hiding at work, which is a core-principal of object-oriented programming.

Furthermore since you don’t have the control of such classes, they might change from version to version. So your application might suddenly breaks.

db4o carful with framework classes

db4o carful with framework classes

You could resolve this problem above by writing your own Color-class. (Which I’ve done in my application). Another approach could be to write a custom object-translator which only stores the relevant information and doesn’t store references to system-resources.

Design Your Data-Model Traversing Friendly

To illustrate this point I go back for a moment to Hibernate & Co. With a object-relational-mapper following many relations is normally a very expensive operation. So I often didn’t actually use the relations and preferred queries instead. So when I designed my persisted classes for Hibernate I often didn’t put every possible relation in there.

Now object-databases are damn good at traversing along the object-references/-relations. So when you’re designing your persisted classes you should keep in mind how you traverse them later. Really focus on the relations between objects and how they interact.

db4o-navigate

So my approach is this. I develop first a domain-model of the problem I try to solve. As soon as I’m happy with my domain-model I begin to draw the directions I need to navigate through the model.

An example. I’ve a color, a car and a driver as domain-objects. Do I ever want to know the cars color? Almost certainly. So I draw a navigation-arrow from the car to the color. Do I ever want to know the colors cars? Probably never. So no navigation-arrow back. With the approach I complete the model step by step with navigation-arrows. After that I’ve a really good idea what I need to persist and which references I need to store.

domain-model

Know Your Compiler / Language

Ok, this is only important in certain scenarios. Again a simple example. I’ve a class which I represents a person.

    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
 

Now you’ve decided to index the Person.Name-property. Now you have to know two things. First is that db4o works with the actual fields of the class. Therefore you declare the indexes at the field-level. (There’s an attribute/annotation for that). But how the hell do you know what fields this class has? Here you really need to know some details of your compiler / language. In this case it the field for the .Name-property is ‘<Name>k__BackingField’. Other .NET-languages might show an other behavior.

db4o compiler, language, platform

db4o compiler, language, platform

Why the hell is this so ugly? As said db4o runs for nearly every Java and .NET version. So the core of db4o is build for the least common features. On top of this are some platform-specific additions like LINQ for .NET. However sometimes some stuff isn’t yet pretty for your platform. Like this auto-property example. So when you hit such a case you might need to know a little more about your language, compiler etc.

To solve the problem above I use a small utility:

    public class Person
    {
        [Indexed]
        public string Name { get; set; }
        public int Age { get; set; }
    }

And then use a extension-method which takes a type. The extension-method adds the indexes according to the attributes:

var cfg = Db4oEmbedded.NewConfiguration();
cfg.Common.IndexClass(typeof(Person));
var db = Db4oEmbedded.OpenFile(cfg, "database.db4o");

The source-code for the utility is at the end of this post.

Read/Try/Ask

This is it for today =). Anyway there are lots of tips and advices out there. In the db4o documentation are some advices how to store some types like Blobs, Collections etc. On this site are some patterns for persistence. However those patterns are mostly for very specific problem which I haven’t encountered yet.

Next Time

Concurrency, oh no, concurrency. =( Next time I give a brief introduction about concurrent operation on a db4o database.

Index-Utility: DBSchemaUtility.cs

Tagged on: , ,