【问题标题】:Is it OK to open a DB4o file for query, insert, update multiple times?是否可以多次打开 DB4o 文件进行查询、插入、更新?
【发布时间】:2010-06-08 15:29:16
【问题描述】:

这就是我正在考虑使用 DB4o 的方式。当我需要查询时,我会打开文件,读取并关闭:

using (IObjectContainer db = Db4oFactory.OpenFile(Db4oFactory.NewConfiguration(), YapFileName))
{
    try
    {
        List<Pilot> pilots = db.Query<Pilot>().ToList<Pilot>();
    }
    finally
    {
       try { db.Close(); }
       catch (Exception) { };
    }
}

稍后,当我需要插入时,然后

using (IObjectContainer db = Db4oFactory.OpenFile(Db4oFactory.NewConfiguration(), YapFileName))
{
    try
    {
        Pilot pilot1 = new Pilot("Michael Schumacher", 100);
        db.Store(pilot1);
    }
    finally
    {
       try { db.Close(); }
       catch (Exception) { };
    }
}

通过这种方式,我认为我可以通过仅在需要时打开文件并在大部分时间关闭文件来保持文件更整洁。但我不断收到 InvalidCastException

Unable to cast object of type 'Db4objects.Db4o.Reflect.Generic.GenericObject' to type 'Pilot'

使用 DB4o 的正确方法是什么?

【问题讨论】:

    标签: db4o


    【解决方案1】:

    不,以这种方式工作不是一个好主意。 db4o ObjectContainer 旨在在您的应用程序运行时始终保持打开状态。几个原因:

    • db4o 维护一个参考系统来识别持久对象,因此当您对已存储的对象(而不是存储新对象)调用#store() 时,它可以进行更新。当您关闭 ObjectContainer 时,此参考系统将关闭,因此无法进行更新。
    • 每次重新打开数据库文件时都必须从数据库文件中读取类元数据。当使用所有持久类时,db4o 还必须再次分析它们的结构。虽然这两种操作都非常快,但您可能不希望每次存储单个对象时都会产生这种开销。
    • db4o 为类和字段索引以及数据库文件本身提供了非常有效的缓存。如果您关闭并重新打开文件,您将无法利用它们。
    • 当您使用多个线程时,您设置代码的方式可能会失败。如果两个线程想要同时打开数据库文件怎么办? db4o 数据库文件只能打开一次。可以针对同一个打开的实例运行多个事务和多个线程,如果您需要多个事务,还可以使用客户端/服务器模式。
    • 稍后您可能想尝试透明激活和透明持久性。透明激活在第一次访问对象成员时会延迟加载它们。透明持久性自动存储在事务中修改的所有对象。要使透明激活 (TA) 和透明持久性 (TP) 正常工作,您当然必须保持 ObjectContainer 处于打开状态。

    您无需担心经常打开数据库文件。 db4o 的主要目标之一是在(移动)设备中的嵌入式使用。这就是为什么我们以这样一种方式编写 db4o,即使文件仍然打开,您也可以随时关闭您的机器而不会造成数据库损坏。

    您获得 GenericObject 而不是 Pilot 对象的可能原因:

    • 当包含 Pilot 对象的程序集的程序集名称在两次运行之间发生更改时,可能会发生这种情况,因为您让 VisualStudio 自动生成名称或因为您手动更改了名称。
    • 也许“db4o”是您的程序集名称的一部分?最近的版本之一在过滤内部类方面过于激进。这已经在很久以前修复了。您可能想下载并尝试最新版本,“开发”或“生产”都可以。
    • 在我曾经做过的一次演示中,当 db4o ObjectContainer 在“使用”块中打开时,我曾经看到过非常奇怪的症状。无论如何,您可能希望在没有它的情况下工作,并始终保持 db4o ObjectContainer 处于打开状态。

    【讨论】:

    • +1 作为 db4o 背后的传奇开发者(任何可以编写如此复杂的数据库的人都必须与 Linus 本人并驾齐驱!)。
    • 卡尔,快速提问。这是我第一个使用 db4o 的项目,我一直在丢失信息。我使用单例模式,我的 ObjectContainer 只打开一次。在每个 .Store() 之后,我从不关闭 ObjectContainer。我对信息丢失的第一个猜测是发生了问题,并且发生了回滚。我的问题是:如果在每个 .Store() 之后关闭连接不是一个好主意,我应该至少在每个 .store() 之后执行一个 .Commit() 吗?
    【解决方案2】:

    可以多次重新打开数据库。问题将是性能和失去“身份”。此外,您不能保留对查询结果的引用并在关闭数据库后尝试对其进行迭代(根据您的代码,看起来您想要这样做)。

    GenericObjects 在找不到类时被实例化。

    您能否提供一个完整的、简约的、不适合您的示例?

    另外,您使用的是哪个 db4o 版本?

    最好的

    【讨论】:

    • 性能:我认为关闭文件而不是担心性能更可取,并且一直保持打开状态,它永远不会关闭。失去“身份”:请您详细说明关闭数据库后的身份参考是什么:不,我没有这样做,我正在使用 DB4o 附带的试点示例程序,我使用的是 7.12 版。谢谢
    • 关于性能:如果您一直打开/关闭数据库,则每次查询对象时都需要加载对象。 失去它的身份我的意思是 db4o 将“忘记”该对象已经存储在数据库中。例如,如果您从 db 中检索一个对象,请关闭/重新打开 db,并且调用 Store() 传递该对象 db4o 将存储该对象的第二个副本。
    • 嗨,快速提问。这是我第一个使用 db4o 的项目,我一直在丢失信息。我使用单例模式,我的 ObjectContainer 只打开一次。在每个 .Store() 之后,我从不关闭 ObjectContainer。我对信息丢失的第一个猜测是发生了问题,并且发生了回滚。我的问题是:如果在每个 .Store() 之后关闭连接不是一个好主意,我应该至少在每个 .store() 之后执行一个 .Commit() 吗?
    • 老问题,但我无法回答我的问题:即使我关闭并重新打开 db4o,我如何才能保持“身份”,执行对象更新?我要疯了才能找到解决方案;我坚持使用 Db4o 的实体会覆盖 Equals 和 GetHashCode 以满足我的更新需求,但我无法让它工作。 :( 我使用的是 Db4o 8.0 版本,嵌入式方式。
    • 像往常一样,在我发布请求 2 分钟后,我找到了解决方案:没有解决方案 :-) 请参阅:community.versant.com/Documentation/Reference/db4o-8.0/net35/…
    猜你喜欢
    • 1970-01-01
    • 2012-09-24
    • 1970-01-01
    • 2013-09-23
    • 1970-01-01
    • 2016-12-04
    • 2011-07-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多