2

This is the way I am thinking of using DB4o. When I need to query, I would open the file, read and close:

using (IObjectContainer db = Db4oFactory.OpenFile(Db4oFactory.NewConfiguration(), YapFileName))
{
    try
    {
        List<Pilot> pilots = db.Query<Pilot>().ToList<Pilot>();
    }
    finally
    {
       try { db.Close(); }
       catch (Exception) { };
    }
}

At some later time, when I need to insert, then

using (IObjectContainer db = Db4oFactory.OpenFile(Db4oFactory.NewConfiguration(), YapFileName))
{
    try
    {
        Pilot pilot1 = new Pilot("Michael Schumacher", 100);
        db.Store(pilot1);
    }
    finally
    {
       try { db.Close(); }
       catch (Exception) { };
    }
}

In this way, I thought I will keep the file more tidy by only having it open when needed, and have it closed most of the time. But I keep getting InvalidCastException

Unable to cast object of type 'Db4objects.Db4o.Reflect.Generic.GenericObject' to type 'Pilot'

What's the correct way to use DB4o?

Kevin Le - Khnle
  • 10,579
  • 11
  • 54
  • 80

2 Answers2

5

No, it's not a good idea to work this way. db4o ObjectContainers are intended to be kept open all the time your application runs. A couple of reasons:

  • db4o maintains a reference system to identify persistent objects, so it can do updates when you call #store() on an object that is already stored (instead of storing new objects) . This reference system is closed when you close the ObjectContainer, so updates won't work.
  • Class Metadata would have to be read from the database file every time you reopen it. db4o would also have to analyze the structure of all persistent classes again, when they are used. While both operations are quite fast, you probably don't want this overhead every time you store a single object.
  • db4o has very efficient caches for class and field indexes and for the database file itself. If you close and reopen the file, you take no advantage of them.
  • The way you have set up your code there could be failures when you work with multiple threads. What if two threads would want to open the database file at exactly the same time? db4o database files can be opened only once. It is possible to run multiple transactions and multiple threads against the same open instance and you can also use Client/Server mode if you need multiple transactions.
  • Later on you may like to try Transparent Activation and Transparent Persistence. Transparent Activation lazily loads object members when they are first accessed. Transparent Persistence automatically stores all objects that were modified in a transaction. For Transparent Activation (TA) and Transparent Persistence (TP) to work you certainly have to keep the ObjectContainer open.

You don't need to worry about constantly having an open database file. One of the key targets of db4o is embedded use in (mobile) devices. That's why we have written db4o in such a way that you can turn your machine off at any time without risking database corruption, even if the file is still open.

Possible reasons why you are getting a GenericObject back instead of a Pilot object:

  • This can happen when the assembly name of the assembly that contains the Pilot object has changed between two runs, either because you let VisualStudio autogenerate the name or because you changed it by hand.
  • Maybe "db4o" is part of your assembly name? One of the recent builds was too agressive at filtering out internal classes. This has been fixed quite some time ago. You may like to download and try the latest release, "development" or "production" should both be fine.
  • In a presentation I once did I have once seen really weird symptoms when db4o ObjectContainers were opened in a "using" block. You probably want to work without that anyway and keep the db4o ObjectContainer open all the time.
Carl Rosenberger
  • 910
  • 6
  • 12
  • 1
    +1 for being the legendary developer behind db4o (anybody who can write a database of that complexity has gotta be right up there with Linus himself!). – Contango Feb 23 '11 at 18:09
  • Carl, quick question. This is my first project with db4o, and I've been experiencing loss of information. I use a Singleton pattern and my ObjectContainer is opened only once. After each .Store() I never close the ObjectContainer. My first guess for the loss of information is that a problem happens, and a rollback takes place. My question is: if it's not a good idea to close the connection after each .Store(), should I at least execute a .Commit() after each .store()? – Gonzalo Mar 06 '12 at 03:24
1

It is ok to reopen the database multiple times. The problem would be performance and loosing the "identity". Also you can't keep a reference to a result of a query and try to iterate it after closing the db (based on you code, looks like you want to do that).

GenericObjects are instantiated when the class cannot be found.

Can you provide a full, minimalist, sample that fails for you?

Also, which db4o version are you using?

Best

Vagaus
  • 4,174
  • 20
  • 31
  • performance: I think it's more preferable to have the file closed instead of worrying about performance, and keep it opened all the time, which it won'tever be closed. Losing the "identity": Could you please elaborate on what is identity reference after close db: no, I'm not doing that I Am pretty much using the pilot sample program that comes with DB4o I am using version 7.12. Thanks – Kevin Le - Khnle Jun 08 '10 at 15:54
  • 1
    Regarding the performance: if you keep opening/closing the db, it will need to load the objects every time you query them. By **loosing its identity** I mean that db4o will "forget" that the object was already store in the database. For instance if you retrieve an object from db close/reopen the db and the call Store() passing that object db4o will store a second copy of that object. – Vagaus Jun 08 '10 at 17:18
  • Hi, quick question. This is my first project with db4o, and I've been experiencing loss of information. I use a Singleton pattern and my ObjectContainer is opened only once. After each .Store() I never close the ObjectContainer. My first guess for the loss of information is that a problem happens, and a rollback takes place. My question is: if it's not a good idea to close the connection after each .Store(), should I at least execute a .Commit() after each .store()? – Gonzalo Mar 06 '12 at 14:38
  • Old question but I cann't get an answer to my problem: how can I mantain "identity", performing object update even if I closed and reopened the db4o? I'm going crazy to find a solution; entities I persist to Db4o overrides Equals and GetHashCode to match my update needs, but I can't get it work. :( I'm using Db4o 8.0 version, Embedded way. – Ferdinando Santacroce May 14 '13 at 14:57
  • As usual, 2 minutes after I posted a request, I found the solution: there's no solution :-) See: http://community.versant.com/Documentation/Reference/db4o-8.0/net35/reference/Content/platform_specific_issues/disconnected_objects.htm – Ferdinando Santacroce May 14 '13 at 15:11