ORMConcurencyException when saving entity with no change

Posts   
 
    
Walter Almeida avatar
Posts: 150
Joined: 27-Aug-2007
# Posted on: 27-Mar-2015 15:44:05   

I have the following issue (using Llblgen 3.1):

When I try saving an entity with no change (isdirty = true, but no field changed from database version), I get an ORMConcurencyException

BTW : this happen when connected to a mySQL database but does not happen with SQL Server

I can understand that saving an entity with no change makes no sense and could be a sign of an concurrency exception. However : in my case i have calculation run on an entity that changes field value but may change it back to original value....

I would therefore want to relax the concurrency check and allow saving an entity with no change. I have tried to implement a concurrency predicate filter but does not help....

Any hint ??

Thanks in advance

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 27-Mar-2015 18:09:52   

Please provide the stack trace and exception text.

Walter Almeida avatar
Posts: 150
Joined: 27-Aug-2007
# Posted on: 27-Mar-2015 21:36:04   

SD.LLBLGen.Pro.ORMSupportClasses.ORMConcurrencyException occurred _HResult=-2146232832 _message=During a save action an entity's update action failed. The entity which failed is enclosed. HResult=-2146232832 IsTransient=false Message=During a save action an entity's update action failed. The entity which failed is enclosed. Source=SD.LLBLGen.Pro.ORMSupportClasses.NET20 RuntimeBuild=02222012 RuntimeVersion=3.1.0.0 StackTrace: at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.PersistQueue(List`1 queueToPersist, Boolean insertActions, Int32& totalAmountSaved) InnerException:

Walter Almeida avatar
Posts: 150
Joined: 27-Aug-2007
# Posted on: 27-Mar-2015 21:38:41   
    e.StackTrace    "   at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.PersistQueue(List`1 queueToPersist, Boolean insertActions, Int32& totalAmountSaved)\r\n   at SD.LLBLGen.Pro.ORMSupportClasses.UnitOfWork2.Commit(IDataAccessAdapter adapterToUse, Boolean autoCommit)\r\n   at PROJ.Data.DataProviders.Database.FormulaDataProvider.DoSaveFromDatabase(IDataAccessAdapter adapter, FormulaDataObject entity, List`1 includes, IObjectsDataSet context) in c:\\Projects\\DataLayerDataProviders\\Database\\FormulaDataProvider.cs:line 187"
daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 28-Mar-2015 06:43:06   

Please provide the exact code that reproduces the exception. Are you sure that the entity you are trying to update does exist in DB?

Quoting the documentation:

ORMConcurrencyException. This exception can be thrown in two situations:

  • During a save of one or more entities. When, during a save action, a save fails, i.e. doesn't affect any rows the exception will be thrown. This can be caused by the fact that the row being updated is already deleted, or the predicate created by the set ConcurrencyPredicateFactory or the passed in predicate caused a failure of the update due to a concurrency violation. The exception will terminate the transaction started during a recursive save and will therefore make a recursive save action completely atomic.
  • During a delete of an entity with a delete restriction. When a delete action of an entity fails and a delete restriction predicate has been specified, for example by an IConcurrencyPredicateFactory, this exception is thrown. Any running transaction will be terminated. A delete action without a delete restriction won't throw this exception, even in the situation the delete failed.
David Elizondo | LLBLGen Support Team
Walter Almeida avatar
Posts: 150
Joined: 27-Aug-2007
# Posted on: 28-Mar-2015 23:26:13   

Ok let me give you a code sample:

var adapter = new DataAccessAdapter(); var linqMetaData = new LinqMetaData(adapter); IQueryable<MyEntity> result = linqMetaData.MyEntity;

// Get existing entity from database, with Id 1 result = result.Where(e => e.Id == 1); var databaseEntity = result.FirstOrDefault();

// store Name value var oldnamevalue = databaseEntity.Name // change Name value to something else (will set entity as dirty) databaseEntity.Name = oldnamevalue + "anything"; // put back original value databaseEntity.Name = oldnamevalue; // save => the SaveEntity call will throw an ORMConcurrencyException adapter.SaveEntity(databaseEntity);

I would need the SaveEntity call to return without throwing an exception. I understand that trying to save an entity with no data change might be a sign of a concurrency problem. But in my case I would need the ORM to ignore this and do the save normally, without considering it as a concurrency exception. Reason : i have calculation code, doing many operations to my entities, sometime ending with entities with several changes cancelling each other (so entity.isdirty = true and no data change ...). I then do a save batch (using unitofwork). I don't want the entities with no change having for effect to rollback the entire transaction...

Is that possible? Thanks in advance

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 30-Mar-2015 07:43:41   

I think that the entity you are trying to update doesn't exist on DB, Can you confirm that. In my opinion, you shouldn't treat a non-existent entity as if it is. So, for instance:

// fetch
var adapter = new DataAccessAdapter();
var linqMetaData = new LinqMetaData(adapter);
IQueryable<MyEntity> result = linqMetaData.MyEntity;
result = result.Where(e => e.Id == 1);
var databaseEntity = result.FirstOrDefault();

// changes
if (!databaseEntity.IsNew)
{
        // store Name value
    var oldnamevalue = databaseEntity.Name
    // change Name value to something else (will set entity as dirty)
    databaseEntity.Name = oldnamevalue + "anything";        
    // put back original value
    databaseEntity.Name = oldnamevalue;
}
David Elizondo | LLBLGen Support Team
Walter Almeida avatar
Posts: 150
Joined: 27-Aug-2007
# Posted on: 30-Mar-2015 09:08:22   

I am sure the entity exist. try the code by yourself with any llblgen pro entity (get an existing data from the DB, change a field value and change it back to original value and then save to DB) and you will get the exception Thanks

Walter Almeida avatar
Posts: 150
Joined: 27-Aug-2007
# Posted on: 30-Mar-2015 09:09:36   

llblgen V3.1

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39859
Joined: 17-Aug-2003
# Posted on: 30-Mar-2015 11:13:35   

check whether rowcounting is switched off in the database (connection settings). Also please check the query being generated (enable dqe tracing, see 'troubleshooting and debugging') and run it directly on the DB to see whether it indeed reports rows affected or not. The concurrency error comes from the fact the db reports 0 rows affected, so the runtime then concludes a concurrency error has occurred and throws the exception.

Frans Bouma | Lead developer LLBLGen Pro
Walter Almeida avatar
Posts: 150
Joined: 27-Aug-2007
# Posted on: 30-Mar-2015 15:12:13   

Ok Frans, Thank you, I understand now how it works.

So, my problem is with MySQL.

If I do this query on SQL Server, on a table customer with a field UserName, and a row with UserName = 'Walter':

UPDATE Customer SET UserName = 'Walter' WHERE UserName = 'Walter'

I get the following result: (1 row(s) affected)

Thefore no ORMConcurrencyException, all is fine.

If I do the same on mySql, I get the following result: 0 row(s) affected Rows matched: 1 Changed: 0 Warnings: 0

So I will get the ORMConcurrencyException....

Is it possible to change something or configure or extend Llblgen to avoid having a concurrency exception thrown in this case? We are effectivelly in a scenario where all is fine and no concurrency occured on the database. I would except the ORM to not throw any exception.

Thanks

Walter Almeida avatar
Posts: 150
Joined: 27-Aug-2007
# Posted on: 30-Mar-2015 18:56:02   

Apparently setting the CLIENT_FOUND_ROWS flag would do the trick. Any way to pass a configuration flag like this one from Llblgen ? Thanks in advance http://dev.mysql.com/doc/refman/5.1/en/mysql-affected-rows.html

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 31-Mar-2015 05:34:39   

Can it be set in the ConnectionString?

Walter Almeida avatar
Posts: 150
Joined: 27-Aug-2007
# Posted on: 31-Mar-2015 08:40:53   

Ok found it, Connection string parameter : FoundRows = True

Found there:

http://www.devart.com/dotconnect/mysql/docs/Devart.Data.MySql~Devart.Data.MySql.MySqlConnection~ConnectionString.html

Does the trick