在db4o本地数据库中存储包含Calendar对象的对象无法检索对象字段

时间:2011-11-04 19:23:45

标签: calendar store db4o

我一直在db4o数据库中存储一个包含GregorianCalendar对象的对象,该工作正常。但是,在检索对象时(关闭并重新打开数据库之后),我似乎无法访问其中的一些信息(即get(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 个答案:

答案 0 :(得分:4)

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 source code中找到这些字段。这些字段通常依赖于对象中的某些其他字段,并在其他字段的值更改时进行计算。从上面的JLS部分:

  

变量可以标记为transient,表示它们不属于对象的持久状态。

例如,假设我有一个代表销售的课程:

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

    // etc...
}

我已将taxesPaid变量声明为瞬态,因为我可以从costtaxRate中找出它。如果成本为2.00美元且税率为7%,则支付的税金为0.14美元。在数据库中,这种信息通常被认为是冗余的,并且有关于如何从数据库中删除这种依赖性的全书。在Java中,您可以通过将其指定为transient来指定该字段根本不存储。

Db4o尊重Java对瞬态字段的定义,它也不会存储它们。实际上,大多数持久性框架和数据库都不会存储瞬态字段。因此,当db4o从数据库重新创建Calendar对象时,它只会恢复其非瞬态字段,这意味着所有瞬态字段都是null(因此您的NullPointerException)。要解决此问题,请告诉db4o:

  • 调用Calendar的构造函数,Calendar构造函数将自动初始化/计算瞬态字段或
  • 存储Calendar的瞬态字段,将字段视为非瞬态字段。

为了记录,我看到人们建议在他们的代码中使用这两行,我也看到GregorianCalendar.class代替Calendar.class。其中一个应该可以正常工作。

抱歉迟到了。我只是认为确保阅读此内容的人知道这是存储Calendar的正确方法很重要(它允许在Calendar字段上进行索引,查询等,而无需对象实例化,从而减慢查询速度)。

答案 1 :(得分:1)

db4o不支持存储日历实例。您应该存储Date实例。

作为替代方案,您可以使用an object translator来存储日历对象。但是不支持对该对象的任何查询。您可以尝试序列化translator,它只使用Java序列化来存储对象:

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

db4o基本上支持存储您自己的“数据”对象,该对象可以包含基元,字符串,数组,基本集合和对其他数据对象的引用。但是,db4o不支持存储复杂的框架对象,如Calendar,Swing-Objects和并发集合等。

然而db4o试图存储任何对象,无论如何。然而,对于具有大量瞬态的复杂对象以及对静态对象的引用,这可能会失败。