how can I validate if there are no errors when executing SaveChangesAsync?

0

I am testing a scenario where I am trying to save a duplicate element and it shows me the following error since the element must be unique (the name and fields of my table are in Spanish, for the example of my code, I preferred to put it in English):

`Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details.
 ---> Microsoft.Data.SqlClient.SqlException (0x80131904): Cannot insert duplicate key row in object 'dbo.Generos' with unique index 'IX_Generos_Nombre'.` **The duplicate key value is (Terror).**`
The statement has been terminated.
   at Microsoft.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__164_0(Task`1 result)
   at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
   at System.Threading.Tasks.Task.<>c.<.cctor>b__274_0(Object obj)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---`

I want to do that if there is any error to save, I can customize the output message and not show the error message.

I also don't understand why the result variable is taken as an int.

[HttpPost]  // I am sending { Nombre: 'Terror'}
public async Task<ActionResult> Post([FromBody] GenreCreationDTO genreCreationDTO)
{
    var entity = mapper.Map<Genre>(genreCreationDTO);
    context.Add(entity);
    var result = await context.SaveChangesAsync(); ///////////////////// problem in this line
    //result is taken as int, why?
    if (!result)
    {
     //show my custom message
    }
     return Ok();
}
c#
entity-framework
asked on Stack Overflow Aug 21, 2020 by yavg • edited Aug 21, 2020 by GSerg

1 Answer

-2

For a simple application, you could query the database before the insert to check if the name (or any other fields you want to be unique) already exists, and if there are results that match that criteria, then return some type of response telling so. Something like this

[HttpPost]
public async Task<ActionResult> Post([FromBody] GenreCreationDTO genreCreationDTO)
{
    var entity = mapper.Map<Genre>(genreCreationDTO);
    var matches = await context.Where(e => e.Name == entity.Name).Select(e => 1).ToListAsync();
   if(matches.Count == 0)
   {
       context.Add(entity);
       var result = await context.SaveChangesAsync();
       return Ok();
   }
   else
   {
     // show custom message
   }  
}

However, keep in mind the above approach will not work 100% for an application used by many clients at the same time. The problem is that there is no guarantee that the thread a request is running on will be suspended after checking if that name already exists but before the insert is done, and while that thread is suspended, another request comes in with the same name and insert the data into the database. Possibly the best thing to do is to handle the exception you are currently receiving in addition to check before the insert if that data already exists. The exception should be rare, it should only occur in a situation similar to the one described above, so, you can choose to not handle it and let the client receive a 500 error, then when the request is retried they will see why the prior request failed, or handle it and determine if the exception indeed occurred because of duplicate data.

As to why the result of SaveChangesAsync is an int, that represents the number of affected rows. In your case, how many rows were inserted.

EDIT: Modified query to include a projection to do SELECT 1 .... instead of SELECT *

answered on Stack Overflow Aug 21, 2020 by Ivan Vargas • edited Aug 21, 2020 by Ivan Vargas

User contributions licensed under CC BY-SA 3.0