Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET Web API - Thread safe logic for updating an entity

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.

like image 635
Nikita Kisel Avatar asked Aug 22 '16 21:08

Nikita Kisel


People also ask

Are entities thread-safe?

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.

Is DbContext thread-safe?

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.

Is rest thread-safe?

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.

What thread-safe means?

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.)


2 Answers

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.

like image 111
Sampath Avatar answered Nov 09 '22 13:11

Sampath


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.

like image 1
Fabian Avatar answered Nov 09 '22 15:11

Fabian