This is a long post but I would really appreciate any response to my questions.
We encountered an issue when trying to refresh entities from the database. We use deep loading to get the stuff into memory. We have to clients running in parallel and do changes on one of the clients. The changes are saved and then it was turn to hit the refresh button in the other client to load the changes in the other client. Now to the programmers surprise it turns out nothing happened.
- What the … (programmer).
- Easy now (that’s me).
After a little investigation we found the following.
To avoid the nuisance of having the same row in the database being represented by several different objects in memory (that sucks if you try to do a DeepSave and also worry about detecting and handling concurrent changes) entity tracking was turned on. Great, we get the same object each time we see that row (good if doing DeepSave no conflict with yourself anymore).
Now what was not so good was that when again calling DeepLoad or GetByPrimaryKey for an already loaded entity it turns out that for example GetByPrimaryKey does the expected thing. It constructs a reader with the latest information from the database. That reader is then passed to the xxxProviderBaseCore.Fill method that is supposed to turn that reader into a TList<xxx> of xxx instances with information from the database. Now this works if we havn’t seen the entity before but in xxxProviderBaseCore.Fill there is a conditional
if (!DataRepository.Provider.EnableEntityTracking || c.EntityState == EntityState.Added)
{
c.SuppressEntityEvents = true;
c.ExerciseID = (System.Guid)reader["ExerciseID"];
c.OriginalExerciseID = c.ExerciseID;
c.DbTimeStamp = (System.Byte[])reader["DbTimeStamp"];
c.EntityTrackingKey = key;
c.AcceptChanges();
c.SuppressEntityEvents = false;
}
rows.Add(c);
that determines whether the information is transferred from the reader onto the object. Now as you can see this will, when entity tracking is enabled, only happen when the object has EntityState.Added which is not the case when you already loaded the object once.
Now, I fail to see why we wouldn’t want to transfer that new fresh information from the database to the object. Is it because we don’t want a load to affect a shared object (I’m currently doing the load in my little part of the process but there are another bunch of modules in this process also having loaded the same object)? Or is the reason performance, i.e. we would spend a lot of time in the DeepLoad scenario trying to set values that already have been set.
Now, there is the xxxProviderBaseCore.RefreshEntity that does exactly what I want, given a reader or a DataSet. I see two possible solutions. Either xxxProviderBaseCore.Fill is allowed to transfer the values read from the database to the object no matter what (i.e. get rid of the “if” but keep the body of it). Or hack a corresponding DeepRefresh framework to get our object graph refreshed from the database.
Now if someone just could enlighten me as to where I’m thinking wrong when wanting to loose the if it might be easier to accept the difference in amount of work implementing the Refresh code (that I feel is currently lacking).
Or the last desperate resort for a quick fix would be to let go of all references to everything you’ve loaded (since weak referencing is used by the Locator in the ObjectBuilder, flush the cache (if it is enabled) and force a garbage collection (wohaaa ….) Now that should hopefully get rid of all references to objects in the object graph letting us once more load the stuff back in with fresh values. (Just the thought of this gives me the creeps).
Thanks for bearing with me this far. Does anyone have any suggestions or comments?