Optimistic Exception Handling

7 posts, 0 answers
  1. Greg
    Greg avatar
    11 posts
    Member since:
    Aug 2014

    Posted 17 Sep 2014 Link to this post

    According to the documentation when there is an OptimisticVerificationException, I can perform a Refresh on the entities that caused the error. However, when I try using RefreshMode.PerserveChanges, I am getting some strange behavior:

    product.Name = "test";

    try
    {
       dbContext.Add(product);
       dbContext.SaveChanges();
    }
    catch (OptimisticVerificationException)
    {
       dbContext.Refresh(RefreshMode.PreserveChanges, product);
       dbContext.SaveChanges();
    }

    After executing the following, I do not see the SQL statements logged from the refresh. It seems as though that before the exception is throw it automatically refreshes the entity and clears all changes. This is not the expected result and does not reflect the information that is displayed in the documentation. Is there some sort of workaround for this?
  2. Doroteya
    Admin
    Doroteya avatar
    502 posts

    Posted 22 Sep 2014 Link to this post

    Hello Greg,

    I understand the inconvenience on your side, and I am sorry about it.

    To achieve the necessary result, you need to re-add the product object to the context in the catch clause like this:
    product.Name = "test";
     
    try
    {
        dbContext.Add(product);
        dbContext.SaveChanges();
    }
    catch (OptimisticVerificationException)
    {
        dbContext.Refresh(RefreshMode.PreserveChanges, product);
        dbContext.Add(product);            //Re-adding the product object to the context
        dbContext.SaveChanges();
    }
    This is required, because when the SaveChanges() call in the try clause failed, the transaction that held the insert operation was rolled back, and in-memory Telerik Data Access restored the state of the product object to its previous one (more information about the object states is available here). This is the reason why you see the loss of the changes (without any log about it) before the call to the Refresh() method. 

    Regarding Refresh(), it does not provide you with the expected result in this case, because the performed changes are already overwritten when the transaction failed. It simply issues a query to the database that should load in-memory the data for the product object.

    Additionally, it would very appreciated, if you could provide us with the link to the documentation article, that mislead you during the implementation.

    I hope this helps. I am looking forward to your feedback.



    Regards,
    Doroteya
    Telerik
     
    OpenAccess ORM is now Telerik Data Access. For more information on the new names, please, check out the Telerik Product Map.
     
  3. DevCraft banner
  4. Greg
    Greg avatar
    11 posts
    Member since:
    Aug 2014

    Posted 22 Sep 2014 in reply to Doroteya Link to this post

    In my particular case I generally always call the Add() method even for updates. In this particular example, it is an update. According to this page (http://docs.telerik.com/data-access/feature-reference/api/context-api/feature-ref-api-context-api-managing-concurrency), it gives the impression that after catching the OptimisticVerificationException that I can manually handle the refreshing of the object. It does not make mention that the object is rolled back to it's initial state. Why is this the behavior? Doesn't this make the OptimisticVerificationException pointless? It makes it really difficult to handle more complicated use cases. I would rather handling the refreshing myself.
  5. Greg
    Greg avatar
    11 posts
    Member since:
    Aug 2014

    Posted 22 Sep 2014 in reply to Greg Link to this post

    After even further analysis it seems that calling Refresh with RefreshMode.PreserveChanges doesn't do anything, while RefreshMode.OverwriteChangesFromStore works properly. I never see a call to the database when using RefreshMode.PreserveChanges.
  6. Doroteya
    Admin
    Doroteya avatar
    502 posts

    Posted 24 Sep 2014 Link to this post

    Hi Greg,

    I am sorry about the misleading you experienced. You can kindly find the details related to your questions, as follows:

    1. Inserting and updating database objects:
    From Telerik Data Access' perspective, insert and update are two different operations and they are handled separately through our API. In the How to: Insert Objects article, you can find information about the insert operation. In the How to: Update Objects article are the details about update.

    2. Transaction Handling:
    In general, SaveChanges() opens a transaction and attempts to execute all specified changes. If every change is persisted successfully, the transaction is committed. If even just one of the changes cannot be executed, all the operations inside the transaction are reverted (the transaction is rolled back). In this article you can find more details.

    3. Concurrency Management:
    I tested the behaviour of the Refresh() method in a concurrency situation, and on my side, calling it with both options lead to one and the same result: the object I called it for was refreshed with the values from the database. In other words, on my side, I observe an additional query to the database that loads the object in-memory. To investigate the outcome you observed on your side, I would suggest to you to create a sample project that reproduces it and send it to us?

    I hope this helps. I am looking forward to your feedback.


    Regards,
    Doroteya
    Telerik
     
    OpenAccess ORM is now Telerik Data Access. For more information on the new names, please, check out the Telerik Product Map.
     
  7. Greg
    Greg avatar
    11 posts
    Member since:
    Aug 2014

    Posted 25 Sep 2014 in reply to Doroteya Link to this post

    Let me clarify my issue because it may be a little difficult to create a simple sample project:

    1) Process A and Process B are running
    2) Process A makes a change to Entity A and then sends a WCF request to Process B to inform it of the change (see http://www.telerik.com/forums/custom-2nd-level-cache-handling for more info as to why I can not use MSMQ).
    3) Process B refreshes its local cache with the changes 

    There will be some rare cases where Step 3 will not occur before Process B attempts to change and save Entity A. Therefore I tried to use the approach that you corrected above to handle this case by calling a Refresh() of the object when the OptimisticVerificationException is thrown. The object is refreshed but it does not preserve the changes even if I call Refresh() with RefreshMode.PreserveChanges (It looks as though it is actually refreshing before I even make my call to Refresh()). I looked at the object life cycle documentation and in my case it gives the impression that I should be able to handle the exception myself. Are you saying that this is incorrect? If it matters I am using VistaDB 5.
  8. Doroteya
    Admin
    Doroteya avatar
    502 posts

    Posted 30 Sep 2014 Link to this post

    Hello Greg,

    Thank you for the additional information.

    I tested your scenario and can confirm that from Telerik Data Access' perspective, the behaviour you experience is the expected one. This happens because, at the time the exception occurs the SaveChanges() method has failed, and the transaction is rolled back. In other words, when you debug you code and you are inside the catch block, the transaction is already rolled back, and the changes are already lost, which is exactly what you observe.

    In the context of the object life-cycle, you have the following workflow:
    1. the object was clean (or notloaded, depending on the previous operations with this object) and when you edited it, its state became dirty,
    2. when you called SaveChanges() it attempted to update the corresponding row in the database, but the transaction failed due to a concurrency conflict,
    3. when the transaction failed, the changes were rolled back, which changed the state of the object to notloaded.

    This process corresponds to line 4 in the Transitions between The Object States table.

    I hope this helps. If you need any additional details, do let us know.


    Regards,
    Doroteya
    Telerik
     
    OpenAccess ORM is now Telerik Data Access. For more information on the new names, please, check out the Telerik Product Map.
     
Back to Top
DevCraft banner