【问题标题】:Prevent orphaned objects in DB4O when updating fields在更新字段时防止 DB4O 中的孤立对象
【发布时间】:2012-10-09 15:22:51
【问题描述】:

我想将 Person 对象存储在 DB4O 中。人员位置字段可以随时间更改。所以我从数据库中检索一个人并调用一个方法来将位置字段设置为一个新的位置对象。 (我希望 Location 对象是不可变的,即 DDD 值对象)。

这可行,但是先前分配的 Location 对象仍保留在数据库中。如何配置 DB4O 以除去这些孤立的 Location 对象?还是我需要一些自定义流程来进行垃圾收集?

本示例的简化类:

class Person {
    Location location;
    public void Move(Location newLocation) { 
        location = newLocation;
    }
}

class Location {
    public Location(string city) { 
        this.City = city;
        //etc
    }
    public readonly string City;
    /// more fields...
}

编辑:更多信息 - Person 是一个 DDD 聚合根。因此,没有对一个人的内部状态的外部引用。如果 Person 更新了它的位置,那么旧的位置应该不复存在了。

【问题讨论】:

    标签: .net db4o orphaned-objects


    【解决方案1】:

    我认为没有完美的解决方案。但是通过一些工作,您几乎可以实现这种行为。类似的话题是already discussed here

    第一步是在位置字段上激活级联删除。所以当一个人被删除时,位置也会被删除。

    configuration.common().objectClass(Person.class).objectField("location").cascadeOnDelete(true);

    现在我们需要处理位置变化的情况。思路是这样的:

    1. 注册激活事件。在那里你“记得”嵌入了哪个对象
    2. 注册更新事件。在那里你检查它是否仍然是同一个嵌入对象。如果没有,你删除旧的。
    3. 非常重要:永远不要“共享”嵌入的对象,否则它将被所有人删除。一个简单的解决方案是在分配位置对象时创建它的副本。

    implements this behavior的Java-Demo。

    嗯,这只是概念,距离可接受的解决方案还有很长的路要走:

    1. 利用属性或其他配置来指定哪些对象是这样的
    2. 构建事件处理程序等的健壮实现。
    3. 确保“共享”位置不被删除的可靠解决方案

    【讨论】:

    • 这是一个很好的答案。我一直在研究使用事件来做到这一点。我很高兴我们同意这是一种可行的方法。
    【解决方案2】:

    你有没有想过把它变成一个值类型?

    【讨论】:

    • 我宁愿不必在顶级对象下方的任何地方都开始使用结构。
    • 是的,这可能是一团糟......他们应该添加从数据库角度将引用对象视为值类型的能力。
    【解决方案3】:

    这对我来说真的像是一笔交易。

    正如 German 所说,您必须删除旧的,存储并分配新的,并确保可以一次性提交这些步骤。

    在 RDBMS 中,您也必须为此提出一个事务。然而,许多 RDBMS 系统在这里为您提供触发器和事件支持。请注意,db4o 还提供某些回调。

    我目前正在为此类情况进行引用计数抽象,但一般处理起来非常棘手。另一方面,您可以编写一个特定的Update 方法,为您简化事务并比较新旧对象的引用。如果它们不匹配并且您可以确定没有其他人引用该类型的地址对象,您可以将其删除。

    另请注意,如果您使用的语言没有垃圾收集,您还必须手动跟踪并删除旧对象。

    “聚合根”的概念对我来说似乎很模糊 - 毕竟,它取决于视角,但这是另一个问题。

    【讨论】:

    • 我正在研究在激活时从根对象遍历对象引用图,存储它,然后在更新时我可以与更新的对象图进行比较。任何遗漏的都可以删除。
    • 这意味着您假设您的位置对象从未被其他任何东西引用过?我仍然认为不应该以某种隐藏的、自动的方式删除对象,但这似乎主要是一个品味问题——毕竟,垃圾收集也是一个很酷的功能。不过,就我个人而言,我还没有准备好在持久数据上使用这样的功能。
    【解决方案4】:

    先在旧位置使用 db4o 的 delete() 然后再存储新位置怎么样?

    最好的!

    德语

    【讨论】:

    • 我使代码示例更能代表我的情况。位置字段是私有的。我希望持久层自动删除旧的位置对象。否则,我必须开始深入挖掘每个对象,然后清理干净。
    【解决方案5】:

    根据cascadeOnDelete(boolean) 的db4o 8.0 API 参考,应该自动删除旧对象。这是文档的副本,请检查给定的示例。

    设置级联删除行为。 将 cascadeOnDelete 设置为 true 将导致删除此类实例的所有成员对象,如果它们被传递给 ObjectContainer.delete(Object)。 小心! 此设置还将在调用 ObjectContainer.store(Object) 时触发删除旧成员对象。 行为示例: 对象容器骗局; 酒吧 bar1 = 新酒吧(); 酒吧 bar2 = 新酒吧(); foo.bar = bar1; con.store(foo); // bar1 存储为 foo 的成员 foo.bar = bar2; con.store(foo); // bar2 存储为 foo 的成员 最后一条语句还将从 ObjectContainer 中删除 bar1,无论有多少其他存储的对象持有对 bar1 的引用。 默认设置为假。 在客户端-服务器环境中,此设置应在客户端和服务器上使用。 此设置可应用于打开的对象容器。 参数: flag - 是否将删除级联到成员对象。 也可以看看: ObjectField.cascadeOnDelete(boolean), ObjectContainer.delete(Object), 使用回调

    但是它不能像打印的那样工作,很奇怪。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-03-28
      • 2013-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-24
      相关资源
      最近更新 更多