我一直在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();
}
}
答案 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
变量声明为瞬态,因为我可以从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 :(得分: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试图存储任何对象,无论如何。然而,对于具有大量瞬态的复杂对象以及对静态对象的引用,这可能会失败。