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

16 posts, 2 answers
  1. Skywalker
    Skywalker avatar
    67 posts
    Member since:
    Sep 2007

    Posted 09 Feb 2011 Link to this post

    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
  2. Skywalker
    Skywalker avatar
    67 posts
    Member since:
    Sep 2007

    Posted 10 Feb 2011 Link to this post

    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.
  3. DevCraft banner
  4. Answer
    Alexander
    Admin
    Alexander avatar
    727 posts

    Posted 14 Feb 2011 Link to this post

    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.
  5. Skywalker
    Skywalker avatar
    67 posts
    Member since:
    Sep 2007

    Posted 14 Feb 2011 Link to this post

    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
  6. Alexander
    Admin
    Alexander avatar
    727 posts

    Posted 17 Feb 2011 Link to this post

    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
  7. Skywalker
    Skywalker avatar
    67 posts
    Member since:
    Sep 2007

    Posted 17 Feb 2011 Link to this post

    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!
  8. Answer
    Alexander
    Admin
    Alexander avatar
    727 posts

    Posted 23 Feb 2011 Link to this post

    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!
  9. Skywalker
    Skywalker avatar
    67 posts
    Member since:
    Sep 2007

    Posted 23 Feb 2011 Link to this post

    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
  10. Alexander
    Admin
    Alexander avatar
    727 posts

    Posted 24 Feb 2011 Link to this post

    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!
  11. Sebastian
    Sebastian avatar
    10 posts
    Member since:
    Sep 2011

    Posted 14 Nov 2012 Link to this post

    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
  12. Alexander
    Admin
    Alexander avatar
    727 posts

    Posted 19 Nov 2012 Link to this post

    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.
  13. Sebastian
    Sebastian avatar
    10 posts
    Member since:
    Sep 2011

    Posted 19 Nov 2012 Link to this post

    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
  14. Alexander
    Admin
    Alexander avatar
    727 posts

    Posted 21 Nov 2012 Link to this post

    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.
  15. David
    David avatar
    3 posts
    Member since:
    May 2013

    Posted 19 Sep 2013 Link to this post

    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
  16. David
    David avatar
    3 posts
    Member since:
    May 2013

    Posted 19 Sep 2013 Link to this post

    Hi

    Yes turning off the 2ndary cache solves the problem.

    Kind Regards

    David
  17. Kaloyan Nikolov
    Admin
    Kaloyan Nikolov avatar
    118 posts

    Posted 24 Sep 2013 Link to this post

    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 >>
Back to Top
DevCraft banner