I have the following method for adding or updating an entity of type Item
for some User. This method is a part of a Service class a new instance of which is created for each request.
public async Task SaveItem(int userId, string name)
{
var item = await _context.Items.Where(i => i.UserId == userId).SingleOrDefaultAsync();
if (item == null)
{
item = new Item
{
UserId = userId,
Name = name
};
_context.Items.Add(item);
}
else
{
item.Name = name;
_context.Entry(item).State = System.Data.Entity.EntityState.Modified;
}
await _context.SaveChangesAsync();
}
The problem is that two concurrent requests may create two items for the same user which is not valid. For me it looks like a pretty common piece of code and I wonder what is the default way of dealing with this kind of concurrency issue.
More that one thread operating on a single Entity Framework context is not thread safe. A separate instance of context for each thread is thread-safe. As long as each thread of execution has its own instance of EF context you will be fine.
DbContext is not thread-safe. Do not share contexts between threads. Make sure to await all async calls before continuing to use the context instance. An InvalidOperationException thrown by EF Core code can put the context into an unrecoverable state.
Currently REST Assured is not entirely thread-safe. The API is written in a way that should allow for concurrency but under the covers it's not.
In computer programming, thread-safe describes a program portion or routine that can be called from multiple programming threads without unwanted interaction between the threads. (A thread is an instance of the program running on behalf of some user or process.)
You have to handle Concurrency Conflicts
properly on your application.
1.Pessimistic Concurrency (Locking)
If your application does need to prevent accidental data loss in concurrency scenarios, one way to do that is to use database locks. This is called pessimistic concurrency. For example, before you read a row from a database, you request a lock for read-only or for update access. If you lock a row for update access, no other users are allowed to lock the row either for read-only or update access, because they would get a copy of data that's in the process of being changed. If you lock a row for read-only access, others can also lock it for read-only access but not for update.
2.Optimistic Concurrency
The alternative to pessimistic concurrency is optimistic concurrency. Optimistic concurrency means allowing concurrency conflicts to happen, and then reacting appropriately if they do.
Please read Handling Concurrency with the Entity Framework article for more info.
If the combination of UserId and Name for an item is supposed to be unique, make it unique in the database.
You could try to solve it with static locking objects... but that will only make it slow and hard to understand/maintain.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With