ORMConcurrencyException - help please

Posts   
 
    
mpawlica
User
Posts: 5
Joined: 17-May-2010
# Posted on: 05-Sep-2013 20:26:09   

Hi everyone,

I'm currently migrating a DAL from LLBL v1.x to v3.1. I already dealt with a lot of stuff, however some issues remain...

The most important one for now is the ORMConcurrencyException. Each user of my app has his own sql server (2005 or 2008, mostly 2008 for now). Sometimes, the users export and import larger parts of data using xml files.

During import, some entities have to be merged. One of them is PlayerEntity. Each player is defined by a GUID PlayerId (this is the primary key), and also has an ExternalId (string), which is used to identify players externally. When importing players, the app searches the local database for a player with the same PlayerId. If no such player is found, another search is performed, this time looking for an ExternalId of the imported player. If one is found, the app was using ForcedCurrentValueWrite in order to change the imported player's PlayerId to the existing player's PlayerId. This part of code looks like this:


PlayerEntity playerExisting = new PlayerEntity(player.PlayerId);
player.IsNew = !adapter.FetchEntity(playerExisting);

if (player.IsNew)
  {
  PlayerEntity dupPlayer = GetPossibleDuplicatePlayer(player, adapter);
  if (dupPlayer != null)
  {
    Guid externalGuid = player.PlayerId;
    player.Fields["PlayerId"].ForcedCurrentValueWrite(dupPlayer.PlayerId);
    player.Fields["PlayerId"].IsChanged = true;
    //player.Fields["PlayerId"].AcceptChange();
    player.IsNew = false;
  }
}

adapter.SaveEntity(player, true);

This used to work on LLBL v1.x that the project was using, with the AcceptChange line uncommented. I'm not sure what was this line for to be honest - it wasn't written by me. However... now, the SaveEntity fails with ORMConcurrencyException. More details:

Message: "During a save action an entity's update action failed. The entity which failed is enclosed."

Stack trace: at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.PersistQueue(List`1 queueToPersist, Boolean insertActions, Int32& totalAmountSaved) at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.SaveEntity(IEntity2 entityToSave, Boolean refetchAfterSave, IPredicateExpression updateRestriction, Boolean recurse) at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.SaveEntity(IEntity2 entityToSave, Boolean refetchAfterSave) at EDH.Tennis.IO.Helpers.ImportHelper.ImportPlayer(XmlTextReader reader, DataAccessAdapter adapter) in C:\Users\Marcin\Desktop\KOD\tennismanager\trunk\EDH.Tennis.IO\Helpers\ImportHelper.cs:line 890

Of course I made sure, that a dupPlayer entity exists in the database when saving, there's no other thread modifying it or anything... Any ideas?

Marcin

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 06-Sep-2013 11:23:35   

Could you please troubleshoot, and post the generated SQL command?

Also I'd have recommended, copying data the other way around, so you fetch the dualPlayer (this is the one in the database, then copy all fields' values from the player, to the dualPlayer, and save the dualPlayer).

mpawlica
User
Posts: 5
Joined: 17-May-2010
# Posted on: 06-Sep-2013 13:31:03   

Walaa, thanks for your response.

I switched on SQLServerDQE tracing and this is the query executed:

Query: UPDATE [TenMan].[dbo].[Player] SET [PlayerID]=@p1, [Gender]=@p2, [Surname]=@p3, [FirstName]=@p4, [Initials]=@p5, [Country]=@p6, [ExternalID]=@p7, [TitleID]=@p8, [ValidSince]=@p9, [NameChanged]=@p10, [ExtSurname]=@p11, [ExtFirstName]=@p12, [SoundsLike]=@p13 WHERE ( [TenMan].[dbo].[Player].[PlayerID] = @p14)
    Parameter: @p1 : Guid. Length: 0. Precision: 0. Scale: 0. Direction: Input. Value: b6e21060-faa0-46e1-abcb-6c6c1b5fb598.
    (...)
    Parameter: @p14 : Guid. Length: 0. Precision: 0. Scale: 0. Direction: Input. Value: 1fc47138-4277-4d8a-96dc-1d0a834cb02e.

The 1fc... GUID is the imported player's PlayerId, and the b6e... GUID is the dupPlayer's PlayerId.

This update had to fail, as there's no 1fc... player in the database, and it's trying to update such record and change it to b6e... PlayerId. It should do the other way around...

After doing some more investigation I found out why did this work in the first place... it was most probably because of the "AcceptChange" call. I think that this call was setting the PlayerId field's IsChanged property to false. I tried doing the same in my code explicitly, and all of a sudden it worked - a querry was generated, which updated the existing record.

If I understand correctly, this is sort of a 'hack', and not the way it should be done. The most correct way would be copying all data (apart from the primary key columns) from the imported record to the local one. I'll try to write a generic method which does that for any entity, and hopefully this will sort my problem out.

Of course, the same code as for players was used to all other entities, so I'll have to change it all around my project...

Anyway, thanks for your help Walaa!

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 06-Sep-2013 21:25:47   

Good to know you find a way around to this. IMHO, when doing those things is better to update the value with adapter.UpdateEntitiesDirectly, as you don't have to deal with Current/DBValues, just a filter and a set of new values.

David Elizondo | LLBLGen Support Team