Mike Taulty's Blog
Bits and Bytes from Microsoft UK
Entity Framework - Object Services Level. Updating and ObjectStateManager.

Blogs

Mike Taulty's Blog

Elsewhere

Following on from the previous post I wanted to apply a similar approach with updating data. If I go and grab the first Shippers record from my store;

      using (NorthwindContext ctx = new NorthwindContext("Name=NorthwindEntities"))
      {
        Shippers single = ctx.Shippers.First();
        DumpObjectStateManager(ctx.ObjectStateManager);

        single.Phone = "Unlisted";
        DumpObjectStateManager(ctx.ObjectStateManager);
      }

Then dumping that ObjectStateManager twice shows that its aware of what's going on here;

Dumping Object State Manager
        Dumping objects in state [Detached]
        Dumping objects in state [Unchanged]
                Entity from entity set [Shippers], key [<Key=ShipperID,Value=1>]

        Dumping objects in state [Added]
        Dumping objects in state [Deleted]
        Dumping objects in state [Modified]


Dumping Object State Manager
        Dumping objects in state [Detached]
        Dumping objects in state [Unchanged]
        Dumping objects in state [Added]
        Dumping objects in state [Deleted]
        Dumping objects in state [Modified]
                Entity from entity set [Shippers], key [<Key=ShipperID,Value=1>]

Now, what's interesting to me is what happens if I run a query that produces a result-set that includes that first record because the framework has to make a choice as to whether it keeps my existing values or overwrites them.

Ok, I lied. I get to make the choice - the framework just has defaults. For instance;

     using (NorthwindContext ctx = new NorthwindContext("Name=NorthwindEntities"))
      {
        Shippers single = ctx.Shippers.First();
        DumpObjectStateManager(ctx.ObjectStateManager);

        single.Phone = "Unlisted";
        DumpObjectStateManager(ctx.ObjectStateManager);

        DumpShippers(ctx.Shippers.Execute(MergeOption.AppendOnly));
        DumpObjectStateManager(ctx.ObjectStateManager);
      }

 

So, here we query for 1 Shipper, we modify it and then we query for all shippers with the AppendOnly option. This is the default and says "Hey, don't you dare overwrite my changes". So, what we end up with at the end of this function (in memory, not in the store) is a set of Shippers;

Dumping
        Shipper id [1], name [Speedy Express], tel [Unlisted]
        Shipper id [2], name [United Package], tel [(503) 555-3199]
        Shipper id [3], name [Federal Shipping], tel [(503) 555-9931]


Dumping Object State Manager
        Dumping objects in state [Detached]
        Dumping objects in state [Unchanged]
                Entity from entity set [Shippers], key [<Key=ShipperID,Value=2>]

                Entity from entity set [Shippers], key [<Key=ShipperID,Value=3>]

        Dumping objects in state [Added]
        Dumping objects in state [Deleted]
        Dumping objects in state [Modified]
                Entity from entity set [Shippers], key [<Key=ShipperID,Value=1>]

So, my modification to the Phone property has been kept as "Unlisted".

What if we went for a different MergeOption such as;

 using (NorthwindContext ctx = new NorthwindContext("Name=NorthwindEntities"))
      {
        Shippers single = ctx.Shippers.First();
        DumpObjectStateManager(ctx.ObjectStateManager);

        single.Phone = "Unlisted";
        DumpObjectStateManager(ctx.ObjectStateManager);

        DumpShippers(ctx.Shippers.Execute(MergeOption.OverwriteChanges));
        DumpObjectStateManager(ctx.ObjectStateManager);
      }

then we end up with my changes being discarded as the "new record comes in from the store";

Dumping
        Shipper id [1], name [Speedy Express], tel [(503) 555-9831]
        Shipper id [2], name [United Package], tel [(503) 555-3199]
        Shipper id [3], name [Federal Shipping], tel [(503) 555-9931]
Dumping Object State Manager
        Dumping objects in state [Detached]
        Dumping objects in state [Unchanged]
                Entity from entity set [Shippers], key [<Key=ShipperID,Value=1>]

                Entity from entity set [Shippers], key [<Key=ShipperID,Value=2>]

                Entity from entity set [Shippers], key [<Key=ShipperID,Value=3>]

        Dumping objects in state [Added]
        Dumping objects in state [Deleted]
        Dumping objects in state [Modified]

there's a couple of other values for MergeOption.

One is "NoTracking" which I think is really your way of saying that you don't want the ObjectStateManager to interfere with you at all. I guess this is because you might be doing something that's "read-only" or you might be trying to do something advanced that you don't want the ObjectStateManager to know about :-)

The other is "PreserveChanges". Whereas OverwriteChanges overwrote my current values I think PreserveChanges would overwrite my original values - I'd imagine that you might use this in a secnario where you've got concurrency problems (I'll investigate concurrency in another post) so for instance;

  1. Pull a record (Key, C1, C2, C3) from the database.
  2. Modify C2 to C2*
  3. Hit a concurrency problem with (say) C3 having been changed by someone else to C3*
  4. Try and refresh your record from the DB. Now, what you want here as original values is (Key, C1, C2, C3*) and as new values (Key, C1, C2*, C3*) and PreserveChanges will give you this whereas OverwriteChanges wouldn't.

If I finally go ahead and actually make changes live in the store then I get the expected result. That is;

   using (NorthwindContext ctx = new NorthwindContext("Name=NorthwindEntities"))
      {
        Shippers single = ctx.Shippers.First();

        single.Phone = "Unlisted";

        ctx.SaveChanges(true);

        DumpObjectStateManager(ctx.ObjectStateManager);
      }

Results in changes to the DB as you'd expect and that final "Dump()" function call produces;

Dumping Object State Manager
        Dumping objects in state [Detached]
        Dumping objects in state [Unchanged]
                Entity from entity set [Shippers], key [<Key=ShipperID,Value=1>]

        Dumping objects in state [Added]
        Dumping objects in state [Deleted]
        Dumping objects in state [Modified]


Posted Mon, Aug 27 2007 4:41 PM by mtaulty

Comments

Mike Taulty's Blog wrote Entity Framework - Object Services Level. Deleting and ObjectStateManager.
on Mon, Aug 27 2007 4:44 PM
Following the general theme of the last couple of posts (here and here), I thought I'd carry on and experiment...
Guy Burstein's Blog wrote ADO.Net Entity Framework Beta 2 is available
on Mon, Aug 27 2007 10:36 PM
ADO.Net Entity Framework Beta 2 is available The ADO.Net Entity Framework bits for Visual Studio 2008
Mike Taulty's Blog wrote ADO.NET Entity Framework - Bringing Together A Few Previous Posts
on Wed, Aug 29 2007 5:38 PM
This is just a convenience - links to the posts that I've made so far around beta 2 of the ADO.NET Entity...
Entity Framework from Mike Taulty « vincenthome’s Software Development wrote Entity Framework from Mike Taulty &laquo; vincenthome&#8217;s Software Development
on Fri, Sep 7 2007 7:25 AM