Identity mapper

D

Dave A

Has anyone written or using an identity mapper design pattern in an
enterprise framework?



The identity mapper pattern is described in Martin Fowler's Patterns of
Enterprise Application Architecture. It means that subsequent loads of the
same object from the database will result in the same object in memory.



Album album1 = Album.Read(10);

Album album2 = Album.Read(10);

Assert.AreSame(album1, album2);



There are some caveats; there is one identity mapper per transaction not per
appdomain and if there is no transaction then a separate identity mapper is
created for that too. Also, when there are no more references to that
object in play then the identity mapper needs to remove the object from its
own internal store. If it did not do this then it means that the identity
mapper is nothing more than a cache that would not be aware of changes to
the underlying data in the db.



This is where my question lies. How can you work out when an object falls
out of scope to notify the identity mapper that the object count has reduced
by one? You could implement IDisposable but then you would need to call
'using' everywhere - not pretty. You could hook into the destructor but then
the behaviour of your code would rely on the scheduling of the garbage
collector - even worse.



You need to ensure that if the following function is called twice in
succession then it actually hits the database twice. If the Album's
destructor was left to notify the identity mapper of album1 falling out of
scope then this notification would not be sent until way after the Function1
was called for the second time.



void Function1()

{

Album album1 = Album.Read(10);

}



Any ideas?



Regards

Dave A
 
F

Frans Bouma [C# MVP]

Dave said:
Has anyone written or using an identity mapper design pattern in an
enterprise framework?

yes. In O/R mapper land, it's called 'uniquing', which means that you
return the same entity instance for a subsequent request of the same
data.
The identity mapper pattern is described in Martin Fowler's Patterns
of Enterprise Application Architecture. It means that subsequent
loads of the same object from the database will result in the same
object in memory.


Album album1 = Album.Read(10);
Album album2 = Album.Read(10);
Assert.AreSame(album1, album2);

There are some caveats; there is one identity mapper per transaction
not per appdomain and if there is no transaction then a separate
identity mapper is created for that too. Also, when there are no
more references to that object in play then the identity mapper needs
to remove the object from its own internal store. If it did not do
this then it means that the identity mapper is nothing more than a
cache that would not be aware of changes to the underlying data in
the db.

it never knows what happens to the DB, as you can't possibly know
that. Take for example a webfarm, or a BL server farm. Multiple
servers, targeting the same large DB server. You don't know what
happens on server A with entity E when your code runs on server B
working with the same entity E.
This is where my question lies. How can you work out when an object
falls out of scope to notify the identity mapper that the object
count has reduced by one? You could implement IDisposable but then
you would need to call 'using' everywhere - not pretty. You could
hook into the destructor but then the behaviour of your code would
rely on the scheduling of the garbage collector - even worse.

You should take a step back. It looks great on paper, this identity
mapper pattern, but in practise it's very hard to implement in a
multi-appdomain system, especially since .NET doesn't have
cross-appdomain object awareness.

Entities are actually pretty abstract things. An entity object isn't
the entity, it's the data inside the entity object which forms the
entity. This means that the actual habitat of the entity isn't an
object, but the DB and in memory you're simply using a mirror, stored
in a container, the Entity object.

If you don't use this approach, but stick with 'the entity == the
entity object', you can't talk about the same 'customer' when you have
two threads on two different machines reading the same data from the
DB. As every sane person will say "that's the same customer", the
entity lives in the db, or better: lives in the shared persistent
storage accessed by all code. This is all highly semantical, but for
understanding what's going on, it's crucial.

Now, Apple's O/R mapper (yes, they have an O/R mapper, which is
actually pretty good, click this url to see what they've cooked up:
http://developer.apple.com/macosx/coredata.html) introduced the concept
of a Context. An entity object is unique within a context. A context is
pure semantical. You can have multiple contexts in one routine if you
like.

LLBLGen Pro, the o/r mapper framework I now work on for 3 years uses
this concept as well. It's actually pretty simple. When you fetch an
entity from the DB (which thus means the data) and store it in an
entity object (its container), the data might be the same as already
loaded versions of that same entity, but the container is a different
instance. To use a Context object you can grab the same instance. So,
if you have a context object in your routine, so it represents a
semantical context, you can pass it to the o/r mapper core when
fetching data and you get for the same entity, the same entity instance
back as was found in the passed in context. You can also consult the
context to get the instance of the entity container for a particular
entity:
CustomerEntity c = (CustomerEntity)myContext.Get(newlyFetchedCustomer);

c is either newlyFetchedCustomer if the entity isn't found in
myContext, or it's the instance which was already known by the context.
'Known by the context' is crucial here: you can have more context
objects in your routine or at runtime, and an entity instance is unique
for a given context, not for a given app at runtime.
You need to ensure that if the following function is called twice in
succession then it actually hits the database twice. If the Album's
destructor was left to notify the identity mapper of album1 falling
out of scope then this notification would not be sent until way after
the Function1 was called for the second time.

void Function1()
{
Album album1 = Album.Read(10);
}

Any ideas?

You shouldn't worry about destruction. After all, the context knows
the instance, so it only goes out of scope when the context goes out of
scope.

FB


--
------------------------------------------------------------------------
Lead developer of LLBLGen Pro, the productive O/R mapper for .NET
LLBLGen Pro website: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------
 
D

Dave A

Many thanks.

I am familiar with this idea of context that has been used by a couple of
different O/R mappers and this leads me on to another point that I am sure
you will be able to shed some light on...

In .Net2 we have the new TransactionScope object. The scope of
TransactionScope seems to be very similiar to the scope of Contexts.

In LLBLGen Pro an entity instance is unique within a context
In an Identity Map and entity instance is unique with in a transaction

I wonder if a brand new O/R mapper were created for .Net2 would the designer
of such an O/R mapper abandon the concept of Contexts and create a new
TransactionScope object (maybe called BusinessScope) that would bring
together transactions and contexts into one concept?

Contexts and transactions start to sound very similar? Only now with
TransactionsScope is the similarity more clear.

Your throughts?

Regards
Dave A
 
F

Frans Bouma [C# MVP]

Dave said:
Many thanks.

I am familiar with this idea of context that has been used by a
couple of different O/R mappers and this leads me on to another point
that I am sure you will be able to shed some light on...

In .Net2 we have the new TransactionScope object. The scope of
TransactionScope seems to be very similiar to the scope of Contexts.

In LLBLGen Pro an entity instance is unique within a context
In an Identity Map and entity instance is unique with in a transaction

I wonder if a brand new O/R mapper were created for .Net2 would the
designer of such an O/R mapper abandon the concept of Contexts and
create a new TransactionScope object (maybe called BusinessScope)
that would bring together transactions and contexts into one concept?

Contexts and transactions start to sound very similar? Only now with
TransactionsScope is the similarity more clear.
Not necessarily, IMHO. The 'transaction' name is a bit odd. Most
people think of an atomic set of actions to manipulate data in a
persistent storage. However used by your example, it's also a set of
actions in memory. I'm not that convinced TransactionScope is meant for
that. It's more a scope object to have persistent storage manipulation
transactionable across systems and objects (COM+/Enterprise services
etc.)

FB
Regards
Dave A


Patterns >> of Enterprise Application Architecture. It means that
subsequent >> loads of the same object from the database will result
in the same >> object in memory.transaction >> not per appdomain and if there is no transaction then
a separate >> identity mapper is created for that too. Also, when
there are no >> more references to that object in play then the
identity mapper needs >> to remove the object from its own internal
store. If it did not do >> this then it means that the identity
mapper is nothing more than a >> cache that would not be aware of
changes to the underlying data in >> the db.
in >> succession then it actually hits the database twice. If the
Album's >> destructor was left to notify the identity mapper of
album1 falling >> out of scope then this notification would not be
sent until way after >> the Function1 was called for the second time.


--
------------------------------------------------------------------------
Lead developer of LLBLGen Pro, the productive O/R mapper for .NET
LLBLGen Pro website: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top