tags:

views:

19

answers:

1

I'm glancing through parts of the official db4o tutorial, and I'm trying to make a modification to the code they give you for running native queries:

//the original
List<Pilot> pilots = db.query(new Predicate<Pilot>() {
    public boolean match(Pilot pilot) {
        return pilot.getPoints() == 100;
    }
});

//modified
List<Pilot> pilots = db.query(new Predicate<Pilot>() {
    public boolean match(Pilot pilot) {
        return pilot.getGames() >= 100;
    }
});

I've added this to their Pilot class:

//in declarations
private ArrayList<String> games;  

//modified constructors
public Pilot() {
    this.name=null;
    this.points=0;
}
public Pilot(String name,int points) {
    this.name=name;
    this.points=points;
    this.games = new ArrayList<String>();
    int numGames = (int) (Math.random() * 1000 + 1);
    for(int i=0;i<numGames;i++) {
        this.games.add(name=" vs Computer");
    }
}

//new method
public int getGames() {
    return games.size();
}

I've already populated a database with 500 objects using the second constructor, and all the data in the db looks correct with the OME eclipse addon. I've tested getGames() and it works as expected.

My problem is that when I run the modified query, it returns all the objects in the db and I don't understand why. I've tried changing the query to include a more standard if true, else false structure and changing the query to include requiring a certain amount of points to no avail. Whatever I do, it seems it always evaluates (pilot.getGames() >= 100) to be true.

Can anyone help me as to understand why?

A: 

Hi

I think you've found a bug. db4o tries to translate the native-queries into a soda-query. This avoid instantiating to objects to perform queries. Now here this translation somehow does not work!

When you turn the optimization off it works. You can do this via configuration:

    EmbeddedConfiguration cfg = Db4oEmbedded.newConfiguration();
    cfg.common().optimizeNativeQueries(false);
    ObjectContainer db = Db4oEmbedded.openFile(cfg,DB_FILE)

However I don't recommend this because then all queries will run slowly. I've found an easy workaround. Change the declaration of the games-field to List<String>. (And other, future List-fields). Like this:

   class Pilot {
         private List<String> games;
         // rest
   }  

This will 'deoptimize' a native query as soon as you access the size() or other methods, hence avoids this bug.

Now a 'deoptimized' query can run quite slow. So if you have lots of objects and the performance is unacceptable I would do this for this query: Create an addional field which stores the current size of the list. Then you use this additional size-field for this kind of query. Additionally you can then index the size-field.

I've reported this as a bug:

Gamlor
Thanks much, sir!
Fusion2004