2010-03-03 5 views
0

Я просматривал часть official db4o tutorial, и я пытаюсь сделать изменения в код, который они дают вам для работающих родных запросов:Проблема с db4o (Java) при выполнении запроса

//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; 
    } 
}); 

Я добавил это их экспериментальный класс:

//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(); 
} 

Я уже заселена база данных с 500 объектами, используя второй конструктор, и все данные в БД выглядит правильно с затмением аддоном OME. Я тестировал getGames(), и он работает так, как ожидалось.

Моя проблема в том, что когда я запускаю измененный запрос, он возвращает все объекты в db, и я не понимаю, почему. Я попытался изменить запрос, чтобы включить более стандартную, если true, else false структуру и изменить запрос, чтобы включить требуемое количество точек безрезультатно. Что бы я ни делал, кажется, он всегда оценивает (pilot.getGames()> = 100) как истинный.

Может ли кто-нибудь помочь мне понять, почему?

ответ

0

Я думаю, вы нашли ошибку. db4o пытается перевести native-queries into a soda-query. Это позволяет не создавать экземпляры объектов для выполнения запросов. Теперь вот этот перевод как-то не работает!

Когда вы выключаете оптимизацию, он работает. Вы можете сделать это через конфигурацию:

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

Однако я не рекомендую это, потому что тогда все запросы будут выполняться медленно. Я нашел легкое обходное решение. Измените объявление поля games на List<String>. (И другие, будущие поля списка). Как это:

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

Это будет «deoptimize» родной запрос, как только вы получаете доступ размера() или другие методы, следовательно, позволяет избежать этой ошибки.

Теперь запрос «deoptimized» может работать довольно медленно. Поэтому, если у вас много объектов, и производительность неприемлема, я бы сделал это для этого запроса: создайте дополнительное поле, в котором хранится текущий размер списка. Затем вы используете это дополнительное поле размера для этого типа запроса. Кроме того, вы можете индексировать поле размера.

Я сообщил this as a bug:

+0

Большое спасибо, сэр! – fusion2004