views:

92

answers:

4

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.

A: 

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

Best!

German

German
I've made the code sample more representative of my situation. The location field is private.I want the persistence layer to automatically delete the old location object. Otherwise I have to start digging down into every object just clean things up.
Andrew Davey
A: 

Have you thought about making it a value type?

Justin Dunlap
I'd rather not have to start using structs everywhere below the top-level object.
Andrew Davey
Yeah, that could be a mess... they should add the ability to treat a reference object as a value type from the database perspective.
Justin Dunlap
A: 

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.

mnemosyn
I'm investigating traversing the object reference graph from a root object upon activation, storing this and then on update I can compare against the updated object graph. Anything missing can be deleted.
Andrew Davey
That means you are assuming your location objects are never ever referenced by anything else? I still don't feel that deletion of objects should take place in some hidden, automatic manner but that seems to be a matter of taste mostly -- after all, garbage collection is a cool feature, too. Personally, I'm not ready for such a feature on persisted data though.
mnemosyn
A: 

Hi

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
Gamlor
This is an excellent answer. I have been investigating using events to do exactly this. I'm glad we agree that it's a viable approach.
Andrew Davey