Tuesday, May 3, 2011

Null key in Identity Map

I have a domain object used in an identity map (the keys are the object's Id property).

Pseudocode:

map = new Mapping();
map[domainObj.Id] = 'foo';

I observe the object to tell me when it has been saved to the database:

domainObj.bind('saved', function() {
    map[domainObj.Id] = 'new foo!'
})

For new objects the Id field is empty and not populated until it is saved to the database.

And therein lies my problem. In the case of new objects, the lookup "map[domainObj.Id]" fails because the object's identity has changed after being saved!

What is the best way to use an object in an identity map like this?

Constraints:

  1. I am using a language that does not allow objects as keys in a mapping [JavaScript]
  2. The Id field must be generated on the server when saving a new object


Update

Thanks for the feedback. I really would like to have value objects mapped the same way as entities: just because the value object has not been saved does not mean it does not have a value to map to for my application. I am in fact mis-understanding what an identity map is (which, after re-reading the pattern definition, it turns out I am not truly using).

The solution I came up with is pretty much straight from Igor's answer: each object gets a random id assigned to it upon instantiation. It is unique, immutable and unchanging during the lifetime of the context in which the object lives. It is there for both entities from the db and new instantiations. The tweak for entities is that it is set to match the real identity of the object. This makes debugging a bit easier. This is the value I use as the key in the mapping.

From stackoverflow
  • Well, you'll have to find a way to postpone adding the object to the map until after it has been saved and assigned an ID.

    JPot : In the sense of the true "Identity Map" pattern you are absolutely right. A value not retrieved from the domain does not belong in the map. Turns out I am not using a real identity map at all but rather a mapping that happens to rely on an "Id" field of an object for lookup-performance reasons (vs scanning a collection).
  • Until an object gets the identity, it's just a value object. Only after the identity has been established it becomes an entity.

    Until the object becomes an entity you cannot really put it in an identity map like yours - it doesn't make sense, since you cannot pull it out (since you don't have a unique key to find it).

    One possible approach:

    1. Add a flag to the class which indicates the state of the object (new / saved).
    2. Implement a temporary (client-side) ID for these objects
    3. Optional:
      1. keep "new" objects in a separate identity map (if you cannot avoid ID conflicts between client and server IDs)
      2. keep "new" objects in the same identity map (if you can avoid ID conflicts between client and server IDs)
    4. Once the object has been saved, replace the client ID with the server ID, set the state to saved, move to the main identity map (if necessary).

    See here about the entities vs. value objects

    Crescent Fresh : What's with that link? I'm in FF and when I click it, I get a 404. I then click into to the address bar (still on the 404 page) and press [Enter], and it works.
    JPot : Thanks. See my updated question for what I settled on doing. The only change is the last part of your answer: once the object has been saved, I don't want to replace the client ID with the server ID since the map is external to the saving and wouldn't know about the updated ID (it's not a real identity map in the "pattern" sense; I was mis-using the term).
    Paco : An entity without Id is still an entity. Keeping a persistent state flag in an entity is not a good idea, because it does not work with the idea of persistence ignorance.
    Igor Brejc : @Paco: what you say may be true, but until you provide a better alternative solution, I think my suggestion still stands. As for entites without ID still being entities: in philosophical terms that's true, but in practical programming terms it's not. A person which doesn't give you his name is still a person, but you wouldn't allow him to register as a voter in a voting application without identifying himself somehow. So until his identity is established, he's not a voting entity :)
    Paco : A value object is immutable. Not every object without id is a value object. In the book from Eric Evans is a really good explanation about this subject.

0 comments:

Post a Comment