Author |
Share Topic Topic Search Topic Options
|
GregD
IdeaBlade
Joined: 09-May-2007
Posts: 374
|
Post Options
Quote Reply
Topic: Handling Concurrency Failures Posted: 11-Jan-2010 at 4:42pm |
Well, it may be that Entity Framework handles this situation differently. All I can really tell you is to comb over the conflicted entity (and drill into the exception that gets thrown) to see if you can identify anything in either that gets set to a value that enables you to identify the conflict uniquely as resulting from an attempt update a remotely deleted entity.
You're looking for anything in the state of the regurgitated entity that is characteristic of that situation only. (That's what I did when I wrote the original version.)
|
|
cjohnson84
Groupie
Joined: 24-Sep-2009
Location: Akron, Ohio
Posts: 44
|
Post Options
Quote Reply
Posted: 11-Jan-2010 at 11:44am |
Here is my code for the refetch
_entityManager.RefetchEntitiesAsync(_entityKeyList, MergeStrategy.PreserveChangesUpdateOriginal, RefetchCallback, null);
Here is what I see in my "RefetchCallback" method for the entity in question. Note my entity in question is a "Client" comprised of ID, FirstName, LastName, TimeStamp (this is my concurrency column on the table):
_currentValues
[0] 19
[1] Chad
[2] Johnson CCJ
_originalValuesBackup
[0] 19
[1] Chad
[2] Johnson
_proposedValuesBackup
[0] 19
[1] Chad
[2] Johnson
CurrentValues
[0] 19
[1] Chad
[2] Johnson CCJ
Nothing was nulled out from what I can tell.
|
|
GregD
IdeaBlade
Joined: 09-May-2007
Posts: 374
|
Post Options
Quote Reply
Posted: 11-Jan-2010 at 11:25am |
I can't swear that I tested (or even addressed) this particular thing in the current WinForm example, but at least back in pre-EntityFramework days (DevForce Classic), the Original values would get a bunch of either nulls or default values (can't remember which) when replaced based on a database record that no longer exists. You could use that to identify the situation you're targetting.
What are you seeing for Original values for your deleted record after the replacement?
|
|
cjohnson84
Groupie
Joined: 24-Sep-2009
Location: Akron, Ohio
Posts: 44
|
Post Options
Quote Reply
Posted: 11-Jan-2010 at 6:03am |
I've run across an issue in trying to implement concurrency conflict handling in my Silverlight application (DevForce 5.2.4.2). I have modeled my concurrency handler after the concurrency handler in the "HandlingConcurrencyConflicts" WinForms sample project in the Learning Resources.
I am trying to verify the case where the local user is attempting to update a record that has already been deleted by another user. I have opened the database in SQL Server management studio and I have also started my application at the same time. I delete a record from the table and then in my application I make an update to the record and then attempt to save. I get a concurrency conflict as expected but I find that because the entity has an original value I end up falling into the block of code that handles the case where the local user and remote user both made changes to the record instead of falling into the block of code that handles the scenario I'm trying to verify.
For further clarification, my code is essentially the same as that in the "ResolveMyConflicts" routine in the "ConcurrencyHandler" class in the Learning Resources sample.
Looking at that routine, the first thing that is done is RefetchEntity is called with the MergeStrategy set to "PreserveChangesUpdateOriginal". If you read the documentation on this MergeStrategy it states:
"The refetch replaces the cached entity's original version with the values from the current data source entity but it preserves the cached entity's current version values thus retaining the pending changes"
I can see where that makes sense for the case where two users make changes to the same record but how would this work in the case where the record doesn't exist in the data source because it was deleted?
What happens to the original version values of the cached entity? Is there a flag I should be looking at that tells me the record in the data source was not found and so the original version values of the cached entity were not replaced from the data source so that I can then move into the correct block of code to handle this particular type of concurrency conflict?
I tried switching to the "PreserveChangesUnlessOriginalObsolete" merge strategy but that takes me into the block of code that handles the case where the local user tries to delete a record that was modified by another user.
Could someone explain to me how this scenario works and where I am going wrong and the Learning Resource sample seems to be going wrong as well?
|
|
skingaby
DevForce MVP
Joined: 23-Apr-2008
Location: United States
Posts: 146
|
Post Options
Quote Reply
Posted: 07-Jan-2010 at 6:05pm |
The default will be for your entities to inherit from Entity. However, if you want to implement any common base entity logic, you will need to add a BaseEntity class (you can change the name) that inherits from Entity and tell the Ideablade Object Mapper to use that as your default Base class.
For example, all of our Oracle tables need a temporary key when they are created, so our BaseEntity class looks like this:
public abstract class BaseEntity : Entity
{
/// <summary>
/// Call to create a new instance of this type in the provided EntityManager.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="emProvider"></param>
/// <returns></returns>
public static T Create<T>(IEntityManagerProvider emProvider) where T : BaseEntity
{
var entity = emProvider.EntityManager.CreateEntity<T>();
entity.Initialize();
return entity;
}
#region Initialize
internal void Initialize()
{
Initializing = true;
GetATemporaryKey();
InitializeDefaults();
BeforeAddToManager();
EntityAspect.AddToManager();
AfterAddToManager();
Initializing = false;
}
private void GetATemporaryKey()
{
var key = EntityAspect.EntityMetadata.KeyProperties[0];
if (key.IsAutoIncrementing)
{
try
{
EntityAspect.EntityManager.GenerateId(this, key);
}
catch (IdeaBladeException ex)
{
//eat the exception thrown if this class does not have a Generator
Logging.Logging.Log(ex);
}
catch (Exception ex)
{
Logging.Logging.Log(ex);
throw;
}
}
}
protected virtual void InitializeDefaults() { }
protected virtual void BeforeAddToManager() { }
protected virtual void AfterAddToManager() { }
public bool Initializing { get; protected set; }
#endregion
} |
|
|
cjohnson84
Groupie
Joined: 24-Sep-2009
Location: Akron, Ohio
Posts: 44
|
Post Options
Quote Reply
Posted: 07-Jan-2010 at 10:01am |
Thank you Greg for explaining. I'm slowly figuring all of this out!
|
|
GregD
IdeaBlade
Joined: 09-May-2007
Posts: 374
|
Post Options
Quote Reply
Posted: 07-Jan-2010 at 9:57am |
You can inject base classes into your model using the Object Mapper, and then specify which other classes you want to inherit from them. The base classes so injected will then be generated by the Object Mapper, and all classes designated to inherit from them will be generated with that inheritance.
I haven't looked at the Concurrency solution for a while, but rather doubt that the use of a BaseEntity is in any way necessary to handle concurrency conflicts. In this as in other uses, a base class is simply a good, economical place to put any methods or properties you'd like all your entities to have.
|
|
cjohnson84
Groupie
Joined: 24-Sep-2009
Location: Akron, Ohio
Posts: 44
|
Post Options
Quote Reply
Posted: 07-Jan-2010 at 8:03am |
Since there is no Silverlight example I have been examining the HandlingConcurrencyConflicts Winforms sample included in the Learning Resources.
Could someone explain to me where the "BaseEntity" class came from that the Customer class inherits from in the code-behind for the domain model?
Examining the "BaseEntity" code the comments state that the class was generated. Is this the case? If so what options in the DevForce Object Mapper were selected to create this class?
When I generate a domain model all of the objects inherit from "Entity" and I don't get a "BaseEntity" class generated.
I am assuming that the "BaseEntity" class was custom written and the author went in and manual edited the code-behind for the domain model by changing the inheritance from "Entity" to "BaseEntity" on the objects in the model.
Is this assumption correct?
|
|
GregD
IdeaBlade
Joined: 09-May-2007
Posts: 374
|
Post Options
Quote Reply
Posted: 05-Jan-2010 at 11:19am |
Sorry, no Silverlight sample yet, but I'll put it on our list.
|
|
cjohnson84
Groupie
Joined: 24-Sep-2009
Location: Akron, Ohio
Posts: 44
|
Post Options
Quote Reply
Posted: 05-Jan-2010 at 7:07am |
Was a Silverlight implementation of concurrency handling ever completed as mentioned above? If so is it available somewhere to download? The only sample in the Learning Resources is for WinForms.
|
|
kimj
IdeaBlade
Joined: 09-May-2007
Posts: 1391
|
Post Options
Quote Reply
Posted: 22-Dec-2009 at 9:01am |
Thanks Simon. I just saw this question yesterday afternoon, and Simon beat me to answering it this morning.
We normally announce the availability of a new release here on the forum, but 5.2.4.x turned out to be a somewhat stealth release. You can always find the latest version and release notes on the Resources/Documentation page of our web site when in doubt.
|
|
cjohnson84
Groupie
Joined: 24-Sep-2009
Location: Akron, Ohio
Posts: 44
|
Post Options
Quote Reply
Posted: 22-Dec-2009 at 7:10am |
I verfied the problem is fixed in 5.2.4.2. Thank you skingaby for your help!
|
|
cjohnson84
Groupie
Joined: 24-Sep-2009
Location: Akron, Ohio
Posts: 44
|
Post Options
Quote Reply
Posted: 22-Dec-2009 at 6:12am |
I'm downloading 5.2.4.2 now. I didn't realize it was released. I'm going to try it and see what happens. Thank you for your help! I appreciate it!
|
|
skingaby
DevForce MVP
Joined: 23-Apr-2008
Location: United States
Posts: 146
|
Post Options
Quote Reply
Posted: 22-Dec-2009 at 6:10am |
I am not sure then. Hopefully kimj will chime in and remind us what the setup needs to be to catch the concurrency failure. I will be looking at it again in the next couple of days. (I finally got my completely redone solution working last night. Yay!)
|
|
skingaby
DevForce MVP
Joined: 23-Apr-2008
Location: United States
Posts: 146
|
Post Options
Quote Reply
Posted: 22-Dec-2009 at 6:08am |
Yes.
|
|
cjohnson84
Groupie
Joined: 24-Sep-2009
Location: Akron, Ohio
Posts: 44
|
Post Options
Quote Reply
Posted: 22-Dec-2009 at 5:36am |
I verified that my Domain Model and my Domain Model project have the same namespace. Is version 5.2.4.2 available for download? I'm not seeing it on the website.
|
|