New Posts New Posts RSS Feed: Differing MergeStrategies among the canned QueryStrategies
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

Differing MergeStrategies among the canned QueryStrategies

 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: Differing MergeStrategies among the canned QueryStrategies
    Posted: 12-Aug-2009 at 12:21pm

My colleague David and I did some exploring of what I call the “Davolio/Smith” Scenario to see what happens when you change the QueryStrategy. The scenario is as follows:

 

Suppose you had fetched all Employees from Northwind. You changed Employee with Id=1 (my good friend, "Nancy Davolio") from "Davolio" to "Smith" ... but you don't save. Now query for employees named "Davolio" using the "Normal", "DatasourceOnly" and "DatasourceThenCache" query strategies. Execute the query with FirstOrNullEntity which returns the first entity found or the null Employee.

 

 I had predicted that

·         With “Normal” , returns NullEntity

·         With “Datasource”, returns ... I wasn’t sure but I hoped for NullEntity

·         With “DatasourceThenCache”, returns NullEntity

 
Why? Although her name is still “Davolio” in the database, she is “Smith” locally and the query should return the local interpretation no matter what the strategy.  There is no employee with the last name "Davolio" in my local cache. Therefore I should get nothing ... and since we executed with FirstOrNullEntity, I should get the null Employee entity.

 

I was surprised to be wrong about the actual results which were.

·         With “Normal” , returns NullEntity (check)

·         With “Datasource”, employee with id=1, name = “Davolio” (Not null entity? not Smith!)

·         With “DatasourceThenCache”, same as “Datasource” (grrr)

 
How could I get the "Davolio" employee? Why is she not "Smith"? I know she can't be both "Smith" and "Davolio" and I know I'm not getting different instances of the Employee with Id == 1.
 
An assumption in my head turned out to be wrong. I thought that the pre-canned QueryStrategies  -- Normal, DatasourceOnly, and DatasourceThenCache -- all used the same MergeStrategy: “PreserveChanges”.

 

That is not so.The DataSource strategies use "OverwriteChanges" which means that my change from "Davolio" to "Smith" was overwritten with the value from the database.

 
While I think that the MergeStrategy should have remained unchanged - should have been PreserveChanges - (as I argued in the thread below), I do not win every argument around here J. To be fair, reasonable minds could differ about what is the best default behavior.

 

Here is a snippet that gives DatasourceThenCache the MergeStrategy that I expected.

   QueryStrategy.DataSourceThenCache.With(MergeStrategy.PreserveChanges) 

 
Accordingly, please take note: the MergeStrategy is not the same across all of the pre-wired QueryStrategies.

 

Lesson #1: Check out all aspects of the QueryStrategy before you use it. The QueryStrategy today consists of three parts

·         FetchStrategy (how and when the EntityManager goes to data source and the cache)

·         MergeStrategy (what to do when a retrieved entity is found in the cache)

·         QueryOptions (other dials)

 

Lesson #2: You may want to create your own QueryStrategies so that they fit your expectations and are used consistently everywhere.

 

The following is the email thread of my journey to enlightenment. Hope you will find the tale cautionary and instructive.

 ------

Sent: Tuesday, August 11, 2009 2:26 PM
To: Ward Bell
Subject: RE: DataSource test

 

Both of these tests pass...

 

  [TestMethod]

  public void DataSourceNormalTest()

  {

      //

      // TODO: Add test logic here

      //

      var _dm = DomainModelEntityManager.DefaultManager;

      var nancy = _dm.Employee.Where(

         e => e.LastName == "Davolio" ).First();

      var originallastname = nancy.LastName;

      nancy.LastName = "Smith";

 

 

      var nancy4q = _dm.Employee.Where(e => e.LastName == "Davolio");

      nancy4q.QueryStrategy = QueryStrategy.Normal;

      var nancy4 = nancy4q.FirstOrNullEntity();

    

      var lastname4 = nancy4.LastName;

      Assert.IsTrue(nancy4.EntityAspect.IsNullEntity);

    

  }

 

  [TestMethod]

  public void DataSourceThenCacheTest()

  {

      //

      // TODO: Add test logic here

      //

      var _dm = DomainModelEntityManager.DefaultManager;

      var nancy = _dm.Employee.Where(

          e => e.LastName == "Davolio").First();

      var originallastname = nancy.LastName;

      

      nancy.LastName = "Smith";

 

      var nancy4q = _dm.Employee.Where(e => e.LastName == "Davolio");

      nancy4q.QueryStrategy = QueryStrategy.DataSourceThenCache;

      var nancy4 = nancy4q.FirstOrNullEntity();

      

      var lastname4 = nancy4.LastName;

      Assert.IsTrue(lastname4 == originallastname);

  }

 ----

From: Ward Bell
Sent: Tuesday, August 11, 2009 3:06 PM
Perhaps you’ve discovered a bug. You have at least discovered anomalous behavior that deserves justification.

 

In your second “DatasourceThenCache” test you look for “Davolio” and find her in the database. You merge the changes … whereupon it is evident that she (employee.Id==1) is “Smith”. After the query has been run against the cache (as part of the “…ThenCache” phase), I would have expected it to return a null entity … because there is no “Davolio” in the cache.

 

In other words, “Normal” and “DatasourceThenCache” should return the same result. The only difference should have been that “DatasourceThenCache” made a trip to the database.

 

What is wrong with my expectation? I thought that “DatasourceThenCache” should be understood as follows:

·         Force query on the database

·         Merge results with the cache

·         Ignore the database query results

·         Re-apply the query as if cache-only

·         Return the cache-only query results


That is obviously not happening if the second query below returns a non-null entity.

--

From: Ward Bell
Sent: Tuesday, August 11, 2009 8:48 PM

My comments back to the chief architect

 --

Sent: Tuesday, August 11, 2009 6:05 PM
To: Ward Bell

 

Ward

                This is the same as it was in Classic and …. It makes sense.  If you are querying “DataSourceOnly” wouldn’t it confuse you if you queried for “Diavolo” and had “Smith” returned? 

 

  EXACTLY. Which is why I thought it should return NULL ENTITY

 

Which is what would happen if we had the MergeStrategy for “DataSourceOnly” be PreserveChanges.   The main idea behind DataSourceOnly is that you get the entities as they look in the database.

 

 I would rather have NULL ENTITY than risk reversing the user’s changes. I concede that reasonable minds may disagree about which is worse. The KEY THING is to know what you’re doing. I’m sure we document it. Like everyone else, I ignore the documentation, fail to test my assumptions, and then I get bitter about it. J



Edited by WardBell - 12-Aug-2009 at 12:31pm
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down