This is a migrated thread and some comments may be shown as answers.

Row not found: GenericOID@1e (...)

15 Answers 1062 Views
Data Access Free Edition
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Skywalker
Top achievements
Rank 1
Skywalker asked on 10 Feb 2011, 05:39 AM
Hi,

I'm experiencing a very strange issue where OpenAccess irregularly throws the following error:

Telerik.OpenAccess.Exceptions.OptimisticVerificationException: Row not found: GenericOID@1e MaleProfile Id=1<br>UPDATE [Profiles] SET [Confidence]=?, [EnergyValue]=?, [Motivation]=?, [Xp]=? WHERE [Id] = ? AND [Xp]=?<br>

This only happens if I repeatedly make a HTTP request really fast to the same url (which will perform an update on a MaleProfile class / record).
I'm storing the OpenAccessObjectContext in Request Scope, and this used to work just fine.
What's also strange is that the row with Id=1 actually does exist: the code doesn't remove that object or anything: it simply wants to update some properties of a MaleProfile where Id = 1. For a few  HTTP requests at a time, it sometimes goes well, and sometimes I receive the mentioned error.

I attached a screenshot of the FireBug window showing the weird behaviour I'm seeing (I expanded one request to show the serverside error after invoking the /executecommand url. As you will see, almost half of these requests fail, all with the same error).

I hope anyone can help me on this weird thing or at least point me into some direction I can look into.

Thanks!

Skywalker

15 Answers, 1 is accepted

Sort by
0
Skywalker
Top achievements
Rank 1
answered on 10 Feb 2011, 07:12 AM
I was able to reproduce the problem and built a small console application demonstrating the issue: http://thedutchpirates.com/downloads/Code/20110210-TestConsole-OA.zip

It basically starts a number of Tasks, where each task creates an ObjectScope, selects the same record, update a column, then call SaveChanges.

static void Main(string[] args)
{
    // To simulate multiple parallel database updates we create a number of tasks and run them in parallel.
             
    var tasks = new List<Task>();
    
    // To make sure we reproduce the error, start a large number of tasks (although 5 tasks will also reproduce the error).
    for (int i = 0; i < 250; i++)
    {
        var task = new Task(() => {
            using (var dc = new ThePBGameContext())
            {
                var profile = dc.Profiles.FirstOrDefault();
 
                // If the database is empty, create a new record
                if (profile == null)
                {
                    profile = new Profile { FirstName = "Jack" };
                    dc.Add(profile);
                }
 
                // Update the record
                profile.Xp++;
 
                // Will throw a conflict exception in one of the tasks
                dc.SaveChanges();
            }
        });
 
        tasks.Add(task);
        task.Start();
    }
 
    // Wait until all tasks have finished
    Task.WaitAll(tasks.ToArray());
 
    Console.WriteLine("Done");
    Console.ReadLine();
}

I checked the Model settings (in the Designer) to ensure the Multithreaded Context checkbox was checked, but I'm not sure if that has anything to do with it.
0
Accepted
Alexander
Telerik team
answered on 14 Feb 2011, 06:48 PM
Hi Skywalker,

Thank you for sending the project, I was able to reproduce the problem. The behavior you observe is caused by the default concurrency control mode used by OpenAccess and is actually expected. The concurrency control mechanism verifies that none of the values of the record being updated has been changed. An OptimisticVerificationException (the one you are getting) will be thrown if the record has been changed by someone else. Having this in mind, the error occurs randomly because the order of the executed tasks cannot be guaranteed and it may happen that a task has read the record and another task performs an update before the first one has committed its changes.
It would be best if you could tell us what is the behavior you expect in this case, so we can help you to choose the most suitable concurrency control mechanism. Do you want to handle and resolve such conflicting changes or the last one to update the record should win, without throwing exceptions?

Greetings,
Alexander
the Telerik team
Accelerate your learning with industry's first Telerik OpenAccess ORM SDK. Download today.
0
Skywalker
Top achievements
Rank 1
answered on 14 Feb 2011, 08:13 PM
Hi Alexander,

Thanks for your reply! What you say makes perfect sense. I guess I assumed that OA would "simply" lock the database in some way, ensuring that each update would be performed sequentially. But I guess that would mean only one request at a time would be allowed to access to the database, which would not be very beneficial in terms of scalability.

Intsead I need to think about how I want the program to act in case of conflicting updates, as you pointed out.

In my particular case, the application needs to increase an integer value of one record and decrease a real value from the same record. Then another record will be updated with some value. It's a sort of payment system: The user pays with Energy to perform some action, which will increase his Experience Points (XP).

So in case of a record that is being read into memory and that same record is being updated from another thread, both changes would ideally be merged somehow. E.g. if the user performs some action three times simultaneously, it should cost him 3 energy points and gain him 3 XP.
Would that be possible somehow?

If not, I think it would be OK to have the last update "win" and discard the previous updates. For the conflicting updates I could send some (user friendly) error to the user that the action could not be performed at this time as it is still "executing".

I will read up some more about the various concurrency control options and how I can best handle conflicts depending on my use case.

In any case, thank you very much for making me aware of what was actually going on!

Regards,
Skywalker
0
Alexander
Telerik team
answered on 17 Feb 2011, 06:47 PM
Hi Skywalker,

As this is really a decision you should make, I will just give you a few tips how to achieve the different approaches with OpenAccess.
In order not to lose any changes, you will have to keep the concurrency control on and handle the OptimisticVerificationException. Once such an exception is caught, you can load the modified object from the database, update its fields and save it. You may need to do this in a loop in case the consecutive updates fail and break after the context.SaveChanges() call succeeds.
If you decide to use the "last update wins" method, you just need to turn the concurrency control off for the class being updated concurrently. This can be done by selecting the class from the diagram and changing its Concurrency Mode property (from the Properties grid) to None.
I hope that helps.

Kind regards,
Alexander
the Telerik team
0
Skywalker
Top achievements
Rank 1
answered on 17 Feb 2011, 09:24 PM
Hi Alexander,

Now that I know the options, I feel like that it would be more natural to handle the concurrency conflict (by comparing the conflicting object with the already stored object and store the XP field with the highest value).

I found this blog post which exactly handles the issue that caused me to start this topic.
It explains how I can check if there is a concurrency issue before commiting the changes, but I am not exactly sure on how to go about loading the already stored record from the database. Would that simply be a matter of selecting the object in question from the already instantiated DataContext, or would I have to new up another DataContext? Or does my object in question need to implement the IDataObjectKey interface so that I can load the already saved version from the database via the DataContext.GetObject() method?

Some advice on this matter would be greatly appreciated.

Thanks for the excellent guidance so far!
0
Accepted
Alexander
Telerik team
answered on 23 Feb 2011, 09:18 AM
Hello Skywalker,

The blog post you refer to actually describes another concurrency control mechanism called "version". This mechanism uses a separate version column to keep a value, which is increased on each update and is used to determine if the record has been updated by someone else. The default mechanism however, does not need such version column as it compares if any of the values of all table columns has been changed. It is again up to you to decide which method to use.

If you go for the version mechanism, you can implement the IDataObjectKey interface and take advantage of the Check method to verify if the object has been changed before calling context.SaveChanges(). Otherwise (with the default mechanism) you will have to surround the SaveChanges method call with a try/catch block and expect the OptimisticVerificationException to be thrown there, as there is no way to check for concurrency conflicts before that. In this case if you catch such an exception, the current transaction will be rolled back, which clears the cache of the context and retrieving the original object from the same context should return you the latest data. If this does not work, you can always use the context.Refresh() method to obtain the latest data at any time.

Regards,
Alexander
the Telerik team
Registration for Q1 2011 What’s New Webinar Week is now open. Mark your calendar for the week starting March 21st and book your seat for a walk through all the exciting stuff we ship with the new release!
0
Skywalker
Top achievements
Rank 1
answered on 23 Feb 2011, 11:09 PM
Hi Alexander,

Thanks!
Ok, I will try out some things and figure out what will work best for my particular case.
With the information you have provided I now have a clear understanding of the options - which are even better than I initially thought.

Thanks again for your time to explain, I learned a lot!

Greets!
Skywalker
0
Alexander
Telerik team
answered on 24 Feb 2011, 07:43 AM
Hello Skywalker,

We are glad to help. Please do get back to us if you need more information.

Kind regards,
Alexander
the Telerik team
Registration for Q1 2011 What’s New Webinar Week is now open. Mark your calendar for the week starting March 21st and book your seat for a walk through all the exciting stuff we ship with the new release!
0
Sebastian
Top achievements
Rank 2
answered on 14 Nov 2012, 09:42 PM
Skywalker,

Did you resolve the problem?

One of our users has the same problem when logging in:


Row not found: GenericOID@cdcacb53 User id=a4b88677-1c8d-4dc3-ae94-8a9bf3f19be7
UPDATE [sf_users] SET [is_backend_user]=?, [last_login_ip]=?, [last_modified]=? WHERE [id] = ? AND [is_backend_user]=? AND [last_login_ip]=?
(set event logging to all to see parameter values)

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: Telerik.OpenAccess.Exceptions.OptimisticVerificationException: Row not found: GenericOID@cdcacb53 User id=----
UPDATE [sf_users] SET [is_backend_user]=?, [last_login_ip]=?, [last_modified]=? WHERE [id] = ? AND [is_backend_user]=? AND [last_login_ip]=?
(set event logging to all to see parameter values)

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.


Stack Trace:

[OptimisticVerificationException: Row not found: GenericOID@cdcacb53 User id=a4b88677-1c8d-4dc3-ae94-8a9bf3f19be7
UPDATE [sf_users] SET [is_backend_user]=?, [last_login_ip]=?, [last_modified]=? WHERE [id] = ? AND [is_backend_user]=? AND [last_login_ip]=?
(set event logging to all to see parameter values)]
   DynamicModule.ns.Wrapped_OpenAccessMembershipProvider_e023fa6ebee24bd3ad6c35353f6136cb.CommitTransaction() +342
   Telerik.Sitefinity.Data.ManagerBase`1.SaveChanges(String eventOrigin) +275
   Telerik.Sitefinity.Security.SecurityManager.Login(ClaimsPrincipalProxy claimsPrincipal, String tokenId, DateTime issueDate) +470
   Telerik.Sitefinity.Security.Claims.SitefinityClaimsAuthenticationModule.AuthenticateRequest(HttpContext context, String rawToken, String tokenType, String[] removeParams) +694
   Telerik.Sitefinity.Security.Claims.SitefinityClaimsAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs args) +749
   System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +80
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +270
0
Alexander
Telerik team
answered on 19 Nov 2012, 04:36 PM
Hello Sebastian,

The error looks like a multithreading or caching issue. Please try the workaround suggested in your support ticket on the same topic:
Set the property Enable data caching to False. The property can be found under Data section of Administration -> Settings -> Advanced menu.

Regards,
Alexander
the Telerik team
Telerik OpenAccess ORM Meets ASP.NET Web API. Read more.
0
Sebastian
Top achievements
Rank 2
answered on 19 Nov 2012, 05:20 PM
Greetings Alexander,

I changed the data caching to False after I received the support ticket answer.

The tricky part here is that this error is very random, I have seen it only twice in last eight months or so.

Thank you,
Sebastian
0
Alexander
Telerik team
answered on 21 Nov 2012, 03:44 PM
Hi Sebastian,

This is the main obstacle for us as well - we cannot consider or perform any fixes if we are unable to isolate the exact faulty scenario, reproduce the error and afterwards confirm that the applied fix is reliable.
Please do get back to us in case this error arises again.

Kind regards,
Alexander
the Telerik team
Telerik OpenAccess ORM Meets ASP.NET Web API. Read more.
0
David
Top achievements
Rank 1
answered on 19 Sep 2013, 06:35 PM
Hi

I am getting this problem too. Slightly different error message.

No row for PlanYourGolf.OpenAccess.GroupMember ('GroupMembers') GenericOID@bf7d8035 GroupMember GM_gId=50c6501a-9293-4965-be6b-63bfc745531c

This occurs after the removal of a row in the Group Members Table.

My tuppance worth is that the ForiegnKey is not being updated on the delete and therefore is trying to find the record in a subsequent cached lookup.

NB: I recently changed OpenAccess options to use the 2ndary cache.

I will turn it off and let you know if it makes a difference.

Kind Regards

David
0
David
Top achievements
Rank 1
answered on 19 Sep 2013, 06:38 PM
Hi

Yes turning off the 2ndary cache solves the problem.

Kind Regards

David
0
Kaloyan Nikolov
Telerik team
answered on 24 Sep 2013, 03:52 PM
Hi David,

In order to help you I'll need more information about your case. What do you try to achieve? Could you provide some code snippets, a sample application demonstrating the problem would be better. 

I am looking forward for your input.

 

Regards,
Kaloyan Nikolov
Telerik
OpenAccess ORM Q3 2013 Beta is available for immediate download in your account. Get it now and play with the latest bits. See what's new >>
Tags
Data Access Free Edition
Asked by
Skywalker
Top achievements
Rank 1
Answers by
Skywalker
Top achievements
Rank 1
Alexander
Telerik team
Sebastian
Top achievements
Rank 2
David
Top achievements
Rank 1
Kaloyan Nikolov
Telerik team
Share this question
or