更新字段时防止 DB4O 中的孤立对象

发布于 2024-08-23 14:52:30 字数 613 浏览 7 评论 0原文

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

这是可行的,但是先前分配的位置对象仍然保留在数据库中。如何配置 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 更新其位置,则旧位置应该不复存在。

I want to store Person objects in DB4O. The Person Location field can be changed over time. So I retrieve a person from the DB and call a method to set the location field to a new Location object. (I want the Location objects to be immutable i.e. DDD Value Objects).

This works, however the previously assigned Location objects remain the database. How can I configure DB4O to remove these orphaned Location objects? Or do I need some custom process to garbage collect?

Simplified classes for this example:

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...
}

EDIT: Some more information - Person is meant to be an DDD aggregate root. So there are no external references to a person's internal state. If Person updates its location, then the old location should cease to exist.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

花海 2024-08-30 14:52:31

对我来说,这确实像是一笔交易。

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

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

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

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

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

This really looks like a transaction to me.

Like German said, you will have to delete the old, store and assign the new one and make sure these steps can be committed in one go.

In a RDBMS, you'd have to come up with a transaction for this, too. However, many RDBMS systems support you here with triggers and events. Note that db4o also offers certain callbacks.

I'm currently working on a ref-count abstraction for cases like this, but it is very tricky to handle generically. On the other hand, you could write a specific Update method that simplifies the transaction for you and compares old and new objects' references. If they don't match and you can be sure that nobody else references that type of address object, you can delete it.

Also note that were you using a language without garbage collection, you'd also have to keep track of this manually and delete the old object.

That 'aggregate root' concept seems very vague to me - after all, it depends on the perspective, but that is another issue.

栩栩如生 2024-08-30 14:52:31

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

最好的!

德语

How about using db4o's delete() first on the old location and then storing the new one?

Best!

German

感受沵的脚步 2024-08-30 14:52:31

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

sets cascaded delete behaviour. 

Setting cascadeOnDelete to true will result in the deletion of all member objects of instances of this class, if they are passed to ObjectContainer.delete(Object). 

Caution !
This setting will also trigger deletion of old member objects, on calls to ObjectContainer.store(Object).

An example of the behaviour:

ObjectContainer con;
Bar bar1 = new Bar();
Bar bar2 = new Bar();
foo.bar = bar1;
con.store(foo); // bar1 is stored as a member of foo
foo.bar = bar2;
con.store(foo); // bar2 is stored as a member of foo 

The last statement will also delete bar1 from the ObjectContainer, no matter how many other stored objects hold references to bar1. 

The default setting is false.

In client-server environment this setting should be used on both client and server. 

This setting can be applied to an open object container. 

Parameters:
flag - whether deletes are to be cascaded to member objects.
See Also:
ObjectField.cascadeOnDelete(boolean), ObjectContainer.delete(Object), Using callbacks

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

According to db4o 8.0 API reference of cascadeOnDelete(boolean), the old object should be deleted automatically. Here is a copy of the doc, check the given example.

sets cascaded delete behaviour. 

Setting cascadeOnDelete to true will result in the deletion of all member objects of instances of this class, if they are passed to ObjectContainer.delete(Object). 

Caution !
This setting will also trigger deletion of old member objects, on calls to ObjectContainer.store(Object).

An example of the behaviour:

ObjectContainer con;
Bar bar1 = new Bar();
Bar bar2 = new Bar();
foo.bar = bar1;
con.store(foo); // bar1 is stored as a member of foo
foo.bar = bar2;
con.store(foo); // bar2 is stored as a member of foo 

The last statement will also delete bar1 from the ObjectContainer, no matter how many other stored objects hold references to bar1. 

The default setting is false.

In client-server environment this setting should be used on both client and server. 

This setting can be applied to an open object container. 

Parameters:
flag - whether deletes are to be cascaded to member objects.
See Also:
ObjectField.cascadeOnDelete(boolean), ObjectContainer.delete(Object), Using callbacks

However it doesn't work as printed, weird.

韬韬不绝 2024-08-30 14:52:30

我认为没有完美的解决方案。但通过一些工作,您几乎可以实现这种行为。类似的主题是 这里已经讨论过

第一步是激活位置字段上的级联删除。因此,当删除一个人时,该位置也会被删除。

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

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

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

Java-Demo 实现了这种行为

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

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

I think there's no perfect solution available. But with some work you can nearly achieve this behavior. A similar topic is already discussed here.

The first step would be to activate cascade-deletion on the location-field. So when a Person is deleted the location is also deleted.

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

Now we need to handle the changing location case. The idea is this:

  1. Register on the activate-event. There you 'remember' which object was embedded
  2. Register on the update-event. There you check if it's still the same embedded object. If not, you delete the old on.
  3. Very important: Never ever 'share' the embedded object, otherwise it will be deleted for everyone. A simple solution is to create a copy of the Location-object whenever it's assigned.

There is Java-Demo which implements this behavior.

Well, this is only the concept, it's a long way to an acceptable solution:

  1. Utilize Attributes or other configuration to specify which objects are such
  2. Build a robust implementation of the event-handlers etc.
  3. A solid solution to ensure that a 'shared' location is not deleted
三生路 2024-08-30 14:52:30

您是否考虑过将其设为值类型?

Have you thought about making it a value type?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文