Base solution for your next web application
Ends in:
01 DAYS
01 HRS
01 MIN
01 SEC
Open Closed

Optimistic Locking #4146


User avatar
0
PhilWynn created

Hi,

I am attempting to implement optimistic locking in order to handle concurrency issues.

I have added the following field to my entities:

[Timestamp]
public byte[] RowVersion { get; set; }

According to the EF documentation, this is all that is required, as long as the initial row version value is supplied with the update. However, I cannot seem to get this to work in ASPNet Zero.

Should I be implementing a custom repository to perform the updates? And if so, how do I prevent the update that is automatically called by the Unit Of Work manager?

Thank you


18 Answer(s)
  • User Avatar
    0
    aaron created
    Support Team

    Did you supply the initial row version? What's not working?

    You should not need to implement a custom repository for this.

  • User Avatar
    0
    PhilWynn created

    Hi,

    Basically, I am not getting a DbUpdateConcurrencyException when I perform a second update on stale data. I have checked that the row version updates in the database, but EF does not object to performing the second update with the old row version.

  • User Avatar
    0
    aaron created
    Support Team
  • User Avatar
    0
    PhilWynn created

    Many thanks, that is probably the issue I am having.

    The (best) solution to this problem is to set the Row Version in the Original Values collection prior to update. I will therefore need to override the update method. I assume the way to do this is via a custom repository?

    If so, how do I get the framework to call this rather than the default Update method? If I call it manually, how do I ensure that the default Update method doesn't get called by the Unit Of Work manager?

    Cheers

  • User Avatar
    0
    aaron created
    Support Team

    I will therefore need to override the update method. I assume the way to do this is via a custom repository?

    Actually, you might want to override ApplyAbpConceptsForModifiedEntity in YourDbContext instead (reason below).

    If so, how do I get the framework to call this rather than the default Update method? If I call it manually, how do I ensure that the default Update method doesn't get called by the Unit Of Work manager?

    The framework (and UnitOfWorkManager) doesn't call Update, but automatically saves changes (incl. ApplyAbpConcepts).

  • User Avatar
    0
    PhilWynn created

    Hi,

    I don't seem to have this method available. I am using v4 of Aspnet Zero, MVC, jQuery.

    Not quite sure how I would achieve my aim with this method anyway?

    Cheers

  • User Avatar
    0
    aaron created
    Support Team

    I don't seem to have this method available.

    Can you show what you did?

    Not quite sure how I would achieve my aim with this method anyway?

    Simple:

    protected override void ApplyAbpConceptsForModifiedEntity(DbEntityEntry entry, long? userId, EntityChangeReport changeReport)
    {
        if (entry.Entity is MyRowVersionEntity)
        {
            entry.OriginalValues["Timestamp"] = entry.CurrentValues["Timestamp"];
        }
    
        base.ApplyAbpConceptsForModifiedEntity(entry, userId, changeReport);
    }
    
  • User Avatar
    0
    PhilWynn created

    Thanks for the explanation.

    I have been unable to code anything, as the version of Abp I am using does not have the ApplyAbpConceptsForModifiedEntity method available for override. The Abp.EntityFramework dll is at version 2.01. I am using aspnet zero v4

  • User Avatar
    0
    aaron created
    Support Team

    You need Abp.EntityFramework v2.3.0, which should be compatible with ASP.NET Zero v4.0 to v4.4. ASP.NET Zero v4.5 to v4.6 should use Abp.EntityFramework v3.1.2.

  • User Avatar
    0
    PhilWynn created

    I'll update and give it a go.

    Many thanks.

  • User Avatar
    0
    PhilWynn created

    Many thanks, the system is now picking up concurrency issue.

    One final problem I am having. I cannot work out how to provide a sensible error message to the users in this instance. The Dynamic Web Api returns a generic message. Is there a way I can override this behaviour when encountering a concurrency exception?

    Cheers

  • User Avatar
    0
    aaron created
    Support Team

    You can override SaveChanges and SaveChangesAsync in YourDbContext:

    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbUpdateConcurrencyException innerException)
        {
            throw new UserFriendlyException("Concurrency exception!", innerException.Message, innerException);
        }
    }
    
  • User Avatar
    0
    PhilWynn created

    Nice. Thank you.

  • User Avatar
    0
    PhilWynn created

    Hi,

    I am having an issue with the upgrade. I have the following service:

    Task<IEnumerable<SelectListItem>> GetPayrollGroupsForDropdown(long? userId);
    

    When I call this service via dynamic web with an 'undefined' parameter, I am getting the following validation error:

    "The value 'undefined' is not valid for Nullable'1"

    This has only started happening since the upgrade.

  • User Avatar
    0
    aaron created
    Support Team

    Please post a new topic. Remember to state which version you upgraded from and to.

  • User Avatar
    0
    tteoh created

    <cite>aaron: </cite> You need Abp.EntityFramework v2.3.0, which should be compatible with ASP.NET Zero v4.0 to v4.4. ASP.NET Zero v4.5 to v4.6 should use Abp.EntityFramework v3.1.2.

    Hi aaron,

    Which version should I upgrade to if I'm using MVC5AJ1? Because I'm not able to upgrade to the latest version, which is version 3.2.3 due to my .NETFramework is 4.6.1

    Thanks. /Tommy

  • User Avatar
    0
    aaron created
    Support Team

    Hi Tommy, can you try Abp.EntityFramework v2.3.0?

  • User Avatar
    0
    tteoh created

    <cite>aaron: </cite> Hi Tommy, can you try Abp.EntityFramework v2.3.0?

    Hi aaron,

    Able to update now.

    What should I do in order to get the exception? Follow the stackoverflow approach?

    Thanks. /Tommy