0

I am using async programming in my c# and I am trying to update data into the db on checking if the records exist else add new record

var existingStudent = await CheckIfStudentExists(student); // check if the Student with the StudentCode is already exist

if (existingStudent is null)
{
    await _context.Students.AddAsync(student);
    await SaveChanges();
}
else
{
    student.StudentId = existingStudent.StudentId;
    _context.Students.Update(student);
    await SaveChanges();
}

Since here I am uploading bulk files (say around 7000) in one shot. It happens that the same StudentCode with 2 different files can comeup. Many times I have observed that ADD part of the code is executed without checking if the student exists.

What is the change I need to do so that If-Else condition is not executed till the CheckIfStudentExists is executed.

Michał Turczyn
  • 32,028
  • 14
  • 47
  • 69
amit agarwal
  • 63
  • 2
  • 17

2 Answers2

1

Well, this code is vulnerable to race condition. Nothing stops two threads checking that student does not exists and enter block of a code where you insert student. This leads to the same student inserted twice.

What you can do is to use some synchronization technique, like locks or semaphore. I will present you the simpliest lock, but it is up to you to choose for yourself how you want synchronize threads.

// somewhere in a class define
private readonly object syncObject = new object();

// and use it in the method
lock(syncObject)
{
    var existingStudent = await CheckIfStudentExists(student); // check if the Student with the StudentCode is already exist

    if (existingStudent is null)
    {
        await _context.Students.AddAsync(student);
        await SaveChanges();
    }
    else
    {
        student.StudentId = existingStudent.StudentId;
        _context.Students.Update(student);
        await SaveChanges();
    }
}
Michał Turczyn
  • 32,028
  • 14
  • 47
  • 69
  • Is there any better way ? not sure I will be allowed to use Lock in this case , as it is costly . – amit agarwal Dec 16 '20 at 12:09
  • @amitagarwal Well, there are plenty of synchronization tools. `Semaphore`, `SemaphoreSlim`, `Monitor` to name a few. – Michał Turczyn Dec 16 '20 at 12:14
  • I checked using lock . And lock do not support await. – amit agarwal Dec 16 '20 at 12:36
  • @amitagarwal check out the [`SemaphoreSlim.WaitAsync`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.semaphoreslim.waitasync) method. It is used by opening a try/finally block immediately after the `await WaitAsync`, and calling `Release` inside the `finally`. The protected region is inside the `try`. – Theodor Zoulias Dec 16 '20 at 16:06
0
if (existingStudent == null)
{
    await _context.Students.AddAsync(student);
    await SaveChanges();
}
else
{
    student.StudentId = existingStudent.StudentId;
    _context.Students.Update(student);
    await SaveChanges();
}
Beso
  • 1,176
  • 5
  • 12
  • 26
  • existingStudent is null and existingStudent == null both does the same thing ? – amit agarwal Dec 16 '20 at 10:22
  • they are different look at [link](https://stackoverflow.com/questions/40676426/what-is-the-difference-between-x-is-null-and-x-null#:~:text=There%20is%20in%20fact%20a,%3D%3D%20operator%20if%20it%20exists.) – Beso Dec 16 '20 at 10:25
  • 1
    While this code may solve the question, [including an explanation](//meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please [edit] your answer to add explanations and give an indication of what limitations and assumptions apply. [From Review](/review/low-quality-posts/27780780) – double-beep Dec 16 '20 at 11:19