How to intercept exceptions when working with the Entity Framework?

7

I want to handle the errors returned by the Entity Framework.

In this example I'm forcing the insertion of a duplicate record (Name already in the database where the column of the table is configured as a Unique Index ):

[HttpPost]
[ValidateAntiForgeryToken]
[Authorization(Roles = "Editar")]
public ActionResult Gravar(Domain.Cidade obj)
{
    if (ModelState.IsValid)
    {
        try {
            if (new App.Cidade().Gravar(obj))
                return RedirectToAction("Listar");
        }
        catch (SqlException e) {
            TempData["Mensagens"] = "Ocorreu um erro enquanto ...";
        }
        catch (EntitySqlException e) {
            TempData["Mensagens"] = "Ocorreu um erro enquanto ...";
        }
        catch (EntityException e) {
            TempData["Mensagens"] = "Ocorreu um erro enquanto ...";
        }
        catch (Exception e) {
            TempData["Mensagens"] = "Ocorreu um erro enquanto ...";
        }
    }
    return View("Cadastro", obj);
}

See what I have separated into three basic types of error handling: SqlException , EntitySqlException , and System.Exception .

But the returned exception is always falling on the treatment for System.Exception .

My save method:

public bool Gravar(Domain.Cidade obj)
{
    var record = context.Cidades.SingleOrDefault(x => x.Id == obj.Id);
    if (record == null)
        context.Cidades.Add(obj);
    else
        context.Entry(record).CurrentValues.SetValues(obj);

    context.SaveChanges();
    return true;
}

How do I get the correct return from the Exception type?

    
asked by anonymous 13.06.2014 / 02:31

3 answers

6

I'll give you an answer that does not directly answer what you want but that will help you and other people for other issues with exceptions.

First we begin by conceptualizing things correctly.

  

But the returned exception is always falling on the treatment for System.Exception

An exception is not returned, it is thrown. It may seem silly but conceptualizing correctly helps you understand the problem and find a solution.

An exception can not be accessed unless it is explicitly captured by catch . So let's rephrase:

  

The exception caught is always System.Exception and not a more specific

If you want to catch a more specific exception, why are you capturing the most general exception of all?

I do not know EF well but according to the other answer it looks like you're wanting to capture the DbUpdateException . And you could have figured it out on your own.

There are two requirements for a programmer to use a catch :

  • know which exception to capture
  • do something useful with the exception, possibly recovering the situation.

Out of use in one of the first methods executed (first levels, perhaps Main ) and basically to log the failure, it is almost 100% sure that capturing Exception is an error .

  • Why do you want to specifically capture a Exception ? Saying it's because you do not know what the correct exception is exactly the best argument to not capture it.
  • And what can you do to recover from any undefined exception? Most likely nothing.

When the program catches a more general exception it is hiding a problem instead of solving it. try/catch abuse seems to be a trend, especially catching Exception . For some reason programmers have taken the belief that the more catch is in the program, the less bugs it will have. And it is exactly the opposite that occurs. I'll repeat: catching a general exception prevents the program from solving a specific problem .

In your problem, you tried to catch SqlException , EntitySqlException , EntityException , and they were not dropped, then another exception was thrown and since any exception is derived from Exception , it dropped there.

Start solving the problem by taking this catch and let the program crash, then you will know what was the exception that caused the problem .

You can even be surprised and find that the problem was somewhere else you did not imagine, that it was a programming error, or a lack of memory (which can occur even if you have enough memory, but this is another matter). You simply do not know what is causing the problem and you are capturing a fault that is possibly unrelated to what you are doing.

Let's see if you can understand what I wrote: once you figure out the correct exception, should you put the snippet back in the program?

    catch (Exception e) {
        TempData["Mensagens"] = "Ocorreu um erro enquanto ...";

I tried to show you how to find the solution by your own means, so you can turn around in other situations. To better understand how exceptions work I've already replied elsewhere: Is it a good practice to throw exceptions in these cases? and < a href="https://en.stackoverflow.com/a/13611/101"> Best way to handle Exceptions .

    
13.06.2014 / 07:25
4

For upgrade errors in Entity Framework 6 + use DbUpdateException :

catch (DbUpdateException e)
{
    System.Console.WriteLine(e.Message);
}

Reference:

13.06.2014 / 03:13
3

You can intercept any exception in your% common% by implementing a Controller for the following method:

protected override void OnException(ExceptionContext filterContext)
{
    /* A exceção fica em filterContext.Exception */
    /* Os detalhes da execução ficam em filterContext.Exception.StackTrace */
}

If you just want to trap only Entity Framework exceptions, follow the script of this answer .

    
13.06.2014 / 18:37