Duplicate key exception from Entity Framework?

Viewed 36672

I'm trying to catch the exception thrown when I insert a already existing user with the given username into my database. As the title says then I'm using EF. The only exception that's thrown when I try to insert the user into to db is a "UpdateException" - How can I extract this exception to identify whether its a duplicate exception or something else?

8 Answers

Now in C# 7 you can use the is operator

// 2627 is unique constraint (includes primary key), 2601 is unique index
catch (UpdateException ex) when (ex.InnerException is SqlException sqlException && (sqlException.Number == 2627 || sqlException.Number == 2601))
{

}

If you need to do the same in Entity Framework Core you can use the library that I built which provides strongly typed exceptions including UniqueConstraintException: EntityFramework.Exceptions

It allows you to catch types exceptions like this:

using (var demoContext = new DemoContext())
{
    demoContext.Products.Add(new Product
    {
        Name = "a",
        Price = 1
    });

    demoContext.Products.Add(new Product
    {
        Name = "a",
        Price = 10
    });

    try
    {
        demoContext.SaveChanges();
    }
    catch (UniqueConstraintException e)
    {
        //Handle exception here
    }
}

All you have to do is install it from Nuget and call it in your OnConfiguring method:

class DemoContext : DbContext
{
    public DbSet<Product> Products { get; set; }
    public DbSet<ProductSale> ProductSale { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseExceptionProcessor();
    }
}

Following @peteski and @Sam

or keyword available since C# 9:

catch (UpdateException ex) when (ex.InnerException is SqlException { Number: 2627 or 2601 })
{

}

For any DB type you can use reflection and the correspondent error number (for MySql 1062):

try
{
    var stateEntries = base.SaveChanges();
}
catch (Exception e)
{
    if(e is DbUpdateException)
    {
        var number = (int)e.InnerException.GetType().GetProperty("Number").GetValue(e.InnerException);
        if (e.InnerException!= null && (number == 1062))
        {
            //your handling stuff
        }
        else
        {
            messages.Add(e.InnerException.Source, e.InnerException.Message);
        }
    }
    else if (e is NotSupportedException || e is ObjectDisposedException || e is InvalidOperationException)
    {
        messages.Add(e.InnerException.Source, e.InnerException.Message);
    }
}
Related