【问题标题】:Storing an object containing a Calender object in a db4o local database, cannot retrieve object fields在 db4o 本地数据库中存储包含 Calender 对象的对象,无法检索对象字段
【发布时间】:2011-12-22 07:35:32
【问题描述】:

我一直在 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();
    }
}

【问题讨论】:

  • 那么,您将几月存储在数据库中,您从中取出的对象是几月?
  • 并不是他们不同,而是抛出了NullPointerException
  • getMonth() 方法(即calendar 字段为null),还是get(GregorianCalendar.MONTH)?还是equals 方法?请帮助解决您的问题。
  • get(GregorianCalendar.MONTH) 抛出异常。检索时日历字段不为空,我已经检查过。
  • 我检查了 API,它说 get() 不应该抛出 NullPointerException。 get(GregorianCalendar.MONTH) 之后的堆栈跟踪是 ' at java.util.Calendar.get(Unknown Source) '

标签: calendar store db4o


【解决方案1】:

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 字段上进行索引、查询等,而无需对象实例化会减慢查询速度)。

【讨论】:

  • 谢谢。在我的情况下,我不再遇到空点异常,但每次检索对象的日历属性时,我只得到当前日期,而不是我存储的日期。关于哪里出了问题的任何想法。
  • 我的建议是将日期存储为字符串,因为 db4o 不支持存储复杂的对象,例如 Calendar、Timestamp 等。但是,db4o 会尝试存储任何对象,但不能保证成功!
  • @AKelec 当然,您可以这样做,但它会大大降低可搜索性。我更愿意将其存储为long 或您自己的自定义数据类型,而不是String,然后比较运算符更容易让你理解,谓词查询和 SODA 查询最终更容易编写和稍后阅读。
【解决方案2】:

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 都会尝试存储任何对象。但是,对于具有大量瞬态和对静态对象的引用的复杂对象,这可能会失败。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-22
    • 1970-01-01
    • 2018-11-04
    • 2019-08-13
    • 1970-01-01
    • 1970-01-01
    • 2021-05-07
    • 2020-11-13
    相关资源
    最近更新 更多