I’m using .net 6 and entity framework.
It’s a most common scenario when a user sign up in the app, the api checks if username available and only create account when it is. Now let’s say two user requesting same username at same time then both the request would find that username is not available and api would allow both of to be created.let’s consider creating new user takes 1 minute in database. How can this can be controlled.
Database lock is one solution but it would create a bottleneck to the application if I’m not wrong. Since it’s a very common scenario, I’m just curious how to handle this best way.
CodePudding user response:
A general concurrency issue is when two users are affecting the same row in the database. Let's say we have an employee and his salary is 3000. Boss increases the salary of an employee to let's say 4000, at the same time, the employee's manager does the same action, but he increases his salary to 3500. EF by default uses an Optimistic Concurrency pattern, so in this case the final salary value would be the last action made on the row. In case boss action was finished first on DB and manager last then the final value would be 3500. The thing is that manager didn't know that boss wanted to increase the employee's salary up to 4000 and he should get some info about it. To prevent such a thing in EF you can use ConcurrencyCheck attribute, so it checks if a value was changed before updating.
[ConcurrencyCheck]
public float Salary{ get; set; }
or use fluent API
modelBuilder.Entity<Employee>()
.Property(p => p.Salary)
.IsConcurrencyToken();
Another way is to use a timestamp, but this is used to protect concurrency issues on a whole row/entity.
[Timestamp]
public byte[] ChangeCheck { get; set; }
It is a special field which gonna be created in DB as ROWVERSION, in this case on SaveChanges it's gonna be checked if the value of ChangeCheck is the same.
In your case there is no affection on the same row, you just want to have the unique value of username. You don't need to lock DB, just mark the username column as UNIQUE and add an index to it to increase performance. The last thing is to catch exceptions on creating new user operation and send a response to a client.
modelBuilder.Entity<User>()
.HasIndex(p => p.Username)
.IsUnique();
