I cannot tell you how many times I’ve had the following conversation
“Hey I’m getting an error”
“What’s the error?”
“DBUpdateException”
“OK, what’s the message though, that could be anything”
“ahhh.. I didn’t see…..”
Frustratingly, When doing almost anything with Entity Framework including updates, deletes and inserts, if something goes wrong you’ll be left with the generic exception of :
Microsoft.EntityFrameworkCore.DbUpdateException: ‘An error occurred while saving the entity changes. See the inner exception for details.’
It can be extremely annoying if you’re wanting to catch a particular database exception (e.g. It’s to be expected that duplicates might be inserted), and handle them in a different way than something like being unable to connect to the database full stop. Let’s work up a quick example to illustrate what I mean.
Let’s assume I have a simple database model like so :
class BlogPost { public int Id { get; set; } public string PostName { get; set; } }
And I have configured my entity to have a unique constaint meaning that every BlogPost must have a unique name :
modelBuilder.Entity<BlogPost>() .HasIndex(x => x.PostName) .IsUnique();
If I do something as simple as :
context.Add(new BlogPost { PostName = "Post 1" }); context.Add(new BlogPost { PostName = "Post 1" }); context.SaveChanges();
The *full* exception would be along the lines of :
Microsoft.EntityFrameworkCore.DbUpdateException: ‘An error occurred while saving the entity changes. See the inner exception for details.’
Inner Exception
SqlException: Cannot insert duplicate key row in object ‘dbo.BlogPosts’ with unique index ‘IX_BlogPosts_PostName’. The duplicate key value is (Post 1).
Let’s say that we want to handle this exception in a very specific way, for us to do this we would have to have a bit of a messy try/catch statement :
try { context.SaveChanges(); }catch(DbUpdateException exception) when (exception?.InnerException?.Message.Contains("Cannot insert duplicate key row in object") ?? false) { //We know that the actual exception was a duplicate key row }
Very ugly and there isn’t much reusability here. If we want to catch a similar exception elsewhere in our code, we’re going to be copy and pasting this long catch statement everywhere.
And that’s where I came across the EntityFrameworkCore.Exceptions library!
Using EntityFrameworkCore.Exceptions
The EntityFrameworkCore.Exceptions library is extremely easy to use and I’m actually somewhat surprised that it hasn’t made it’s way into the core EntityFramework libraries already.
To use it, all we have to do is run the following on our Package Manager Console :
Install-Package EntityFrameworkCore.Exceptions.SqlServer
And note that there are packages for things like Postgres and MySQL if that’s your thing!
Then with a single line for our DB Context we can set up better error handling :
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseExceptionProcessor(); }
If we run our example code from above, instead of our generic DbUpdateException we get :
EntityFramework.Exceptions.Common.UniqueConstraintException: ‘Unique constraint violation’
Meaning we can change our Try/Catch to be :
try { context.SaveChanges(); }catch(UniqueConstraintException ex) { //We know that the actual exception was a duplicate key row }
Much cleaner, much tidier, and far more reusable!