New Posts New Posts RSS Feed: AttachEntity and AddEntity
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

AttachEntity and AddEntity

 Post Reply Post Reply
Author
WardBell View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Mar-2009
Location: Emeryville, CA,
Posts: 338
Post Options Post Options   Quote WardBell Quote  Post ReplyReply Direct Link To This Post Topic: AttachEntity and AddEntity
    Posted: 21-Aug-2009 at 3:15pm

We are adding an AttachEntity(object entity) method to the EntityManager in release 5.2.2.

Those of you who write test and don't want those tests to touch the database will appreciate this the most.
 
As you know, you sometimes need to write tests which rely upon interaction with the EntityManager. You want to populate a disconnected EntityManager with a small collection of hand-rolled stub entities. While such tests are integration tests because they rely on a dependency, we still want to make them easy to write and we want them to be fast. That means we don't want a trip to a database when we run them; we shouldn't need to have a database to run them.
 
I usually start by creating a test-oriented, disconnected EntityManager ... which can be as simple as
 
   var testManager = new EntityManager(false /* disconnected */ );
 
The easiest way to get a stub entity is to "new" it up, set some of its properties, give it an EntityKey, and dump it in our testManager. when we're done it should appear there as an unchanged entity ... as if you had read it from the datastore.
 
The catch is "how do I add the entity to the manager?"
 
In the absence of AttacheEntity you are likely to have used EntityManager.AddEntity. But after AddToManager, the EntityState of the entity is always "Added". You want "Unchanged" so you have to remember to call AcceptChanges (which changes the state to "Unchanged").
 
That's not too hard. Unfortunately, it gets messy if the key of the entity is auto-generated (e.g., mapped to a table whose id field is auto-increment) because DevForce automatically replaces your key with a temporary one as part of its auto-id-generation behavior.
 
I could explain how to work around this. What a PITA. We really just want a simple way to simulate the result of retrieving an entity. That's why we now have AttachEntity.
 
Here's the XML documentation for AttachEntity:
 

Adds a detached entity to this EntityManager in an Unmodified state. 

Throws an exception if an entity with the same key already exists in the manager
of if the specified entity is not in a detached state.
 
Let me elaborate here and compare it to some similar methods by calling out the following facts about the following code fragment:
 
   theEntityManager.AttachEntity(object theEntity)
 

1.       theEntity’s EntityKey (“the key”) must be preset prior to the attach operation which will not touch the key

2.       An exception is thrown if an entity with that key is already in the cache

3.       After attach, theEntity is in an “Unchanged” EntityState (“the state”)

4.       theEntity is presumed to exist in the persistent store;  subsequent change and save will translate to an update statement.

5.       After successful attach, a reference to theEntity is a reference to the entity with that key in the manager’s EntityCache; contrast with anEntityManager.Imports(new [] {anEntity})” as discussed below.

6.       theEntity must be in the “Detached” state prior to the operation

7.       An exception is thrown if theEntity is other than in “Detached” state prior to the operation

8.       After attach, related entities are implicitly associated with theEntity automatically; for example, if anOrder with Id==22 is attached and there are OrderDetails with parent OrderId==22, then after the attach, anOrder.OrderDetails returns these details and any one of them will return ‘anOrder’ in response to anOrderDetail.Order.

9.       The sequence of attachments is not important; OrderDetails may be added prior to the parent Order;

10.   Attach has no effect on theEntityManager’s QueryCache

 

AttachEntity and AddEntity behave the same way except:

 

11.   After add, theEntity is in an “Added” state

12.   theEntity is presumed to be new and to be absent from in the persistent store; a save will translate to an insert statement.

13.   If the key for this type is auto-generated (e.g., backed by an auto-increment field in the database), the existing key will be set to a generated temporary key, replacing the prior key value.

 

The following is true regarding detaching anEntity:

 

14.   After detach, anEntity enters the “Detached” state no matter what its prior state.

15.   Detaching an Order does not detach its child OrderDetails; they remain “orphaned” in the cache

16.   The sequence of detachments is not important; an Order may be detached prior to detaching its child OrderDetails

17.   Detach has no effect on theEntityManager’s QueryCache

 

EntityManager.Imports is another way of populating an EntityManager with a collection of entities that may have come from anywhere (including hand-rolled). Here's how you might "import" a single stub entity:

    theEntityManager.Imports(new [] {theEntity})
 
Imports differs from AttachEntity in that:

 

18.  it requires a MergeStrategy to tell it what to do if an entity with the same key as "theEntity" already exists in the cache.

19.  it merges "theEntity" into the cache based on the MergeStrategy

20.   it makes a clone of "theEntity" and adds that clone to the EntityCache ... unless "theEntity" happens to already be in the cache in which case it is ignored ... which means that

21.   using our example and assuming that "theEntity" was not already in the manager, the entity instance in the cache is not the same as the entity instance you imported, although their keys are equal; the following is true:

      theEntity != theManager.FindEntity(theEntity.EntityAspect.EntityKey)

22.  A "clone" is a copy of an entity, equivalent to calling ((ICloneable)theEntity).Clone(); 

23.  This is a copy of the entity, not of its related entities.

 
Enjoy!
Back to Top
WardBell View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Mar-2009
Location: Emeryville, CA,
Posts: 338
Post Options Post Options   Quote WardBell Quote  Post ReplyReply Direct Link To This Post Posted: 21-Aug-2009 at 4:41pm

Another, important difference between AttachEntity and ImportEntities:

You can only import entities which already belong to an EntityManager (i.e., are not "Detached"). This means that
 
  theEntityManager.Imports(new [] {theEntity})
 
will throw an exception if "theEntity" is a detached, hand-rolled stub (as of v.5.2.2).
 
Import still fulfills admirably its primary purpose which is to copy entities from one EntityManager to another.
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down