При хранении объекта, содержащего объект Calender, в локальной базе данных db4o, невозможно получить поля объекта - PullRequest
2 голосов
/ 04 ноября 2011

Я храню объект, который содержит объект GregorianCalendar в базе данных db4o, который работает просто отлично. Однако при извлечении объекта (после закрытия и повторного открытия базы данных) я не могу получить доступ к некоторой информации внутри (а именно, получить (GregorianCalendar.MONTH)). Я включил тестовый код ниже, и мне интересно, как решить эту проблему.

import static org.junit.Assert.assertEquals;

import java.util.GregorianCalendar;

import org.junit.Test;

import com.db4o.Db4oEmbedded;
import com.db4o.ObjectContainer;
import com.db4o.config.EmbeddedConfiguration;

public class DateTest {

    public class RecordDate {

        private GregorianCalendar calendar;

        public RecordDate() {
            calendar = new GregorianCalendar();
        }

        public int getMonth() {
            return calendar.get(GregorianCalendar.MONTH);
        }
    }

    @Test
    public void testGetMonth() {
        EmbeddedConfiguration config = Db4oEmbedded.newConfiguration();
        config.common().objectClass(RecordDate.class).cascadeOnActivate(true);
        config.common().objectClass(RecordDate.class).cascadeOnUpdate(true);
        config.common().activationDepth(25);
        config.common().updateDepth(25);

        ObjectContainer database = Db4oEmbedded.openFile(config,
                "db/datetest.db");

        GregorianCalendar currentdate = new GregorianCalendar();
        RecordDate testdate = new RecordDate();
        assertEquals(currentdate.get(GregorianCalendar.MONTH),
                testdate.getMonth()); // this passes

        database.store(testdate);
        database.close();

        EmbeddedConfiguration config2 = Db4oEmbedded.newConfiguration();
        config2.common().objectClass(RecordDate.class).cascadeOnActivate(true);
        config2.common().objectClass(RecordDate.class).cascadeOnUpdate(true);
        config2.common().activationDepth(25);
        config2.common().updateDepth(25);
        database = Db4oEmbedded.openFile(config2, "db/datetest.db");

        testdate = (RecordDate) database.queryByExample(RecordDate.class)
                .next();
        assertEquals(currentdate.get(GregorianCalendar.MONTH),
                testdate.getMonth()); // this should pass, but doesn't
        database.close();
    }
}

Ответы [ 2 ]

4 голосов
/ 23 декабря 2011

Db4o поддерживает java.util.Calendar объекты, но не из коробки. Чтобы добавить поддержку Calendar, добавьте одну из этих двух строк в конфигурацию базы данных:

configuration.common().objectClass(Calendar.class).callConstructor(true);

или

configuration.common().objectClass(Calendar.class).storeTransientFields(true);

Причина, по которой это необходимо, состоит в том, что Calendar имеет transient поля или поля, которые не сохраняются или не сериализуются по умолчанию в Java ( JLS §8.3.1.3 ). Вы можете найти эти поля в Calendar исходном коде , если хотите. Эти поля обычно зависят от какого-либо другого поля в объекте и вычисляются при изменении значения другого поля. Из раздела JLS выше:

Переменные могут быть помечены transient, чтобы указать, что они не являются частью постоянного состояния объекта.

Например, допустим, у меня есть класс, представляющий продажу:

public class Sale {
    private double cost, taxRate;
    private transient double taxesPaid;

    // etc...
}

Я объявил здесь переменную taxesPaid как переходную, потому что могу понять это из cost и taxRate. Если стоимость составляет 2,00 доллара США, а ставка налога составляет 7%, то уплаченные налоги составят 0,14 доллара США. В базах данных этот вид информации обычно считается избыточным, и есть целые книги, написанные о том, как удалить этот вид зависимости из базы данных. В Java вы можете указать, что поле не будет сохраняться вообще, указав его как transient.

Db4o соблюдает определение переходных полей в Java и не будет их хранить. Фактически, большинство постоянных структур и баз данных не будут хранить временные поля. Таким образом, когда db4o воссоздает объект Calendar из базы данных, он только восстанавливает свои непереходные поля, что означает, что все переходные поля равны null (следовательно, ваш NullPointerException). Чтобы это исправить, вы указываете db4o либо:

  • Вызовите конструктор Calendar, и конструктор Calendar автоматически инициализирует / вычислит переходные поля или
  • Сохраните Calendar переходные поля, которые будут обрабатывать поля, как если бы они не были переходными.

Кстати, я видел, как люди рекомендуют использовать обе строки в своем коде, и я также видел GregorianCalendar.class вместо Calendar.class. Хотя один или другой должен работать нормально.

Извините за взвешивание в конце. Я просто подумал, что важно убедиться, что любой, кто читает это, знает, что это правильный способ хранения Calendar (он позволяет индексировать, запрашивать и т. Д. В полях Calendar без создания объектов, замедляющих запросы).

1 голос
/ 08 ноября 2011

db4o не поддерживает хранение экземпляров календаря. Вы должны хранить экземпляры Date.

В качестве альтернативы вы можете использовать переводчик объектов для хранения вашего календарного объекта. Однако, это не будет поддерживать какой-либо запрос по этому объекту. Вы можете попробовать сериализовать переводчик , который просто использует сериализацию Java для хранения объекта:

configuration.common().objectClass(Calendar.class).translate(new TSerializable());
configuration.common().objectClass(GregorianCalendar.class).translate(new TSerializable());

db4o в основном поддерживает хранение вашего собственного объекта данных, который может состоять из примитивов, строк, массивов, базовой коллекции и ссылок на другие объекты данных. Однако db4o не поддерживает хранение сложных каркасных объектов, таких как Calendar, Swing-Objects, одновременных коллекций и т. Д.

Однако db4o пытается сохранить любой объект, несмотря ни на что. Однако со сложным объектом с тоннами переходного состояния и ссылками на статические объекты это может завершиться ошибкой.

...