Finding the reason for DBUpdateException

C#.NetEntity Framework

C# Problem Overview


When calling DbContext.SaveChanges, I get a DbUpdateException:

> An unhandled exception of type > 'System.Data.Entity.Infrastructure.DbUpdateException' occurred in > EntityFramework.dll. Additional information: An error occurred while > updating the entries. See the inner exception for details.

Unfortunately, there is no inner exception (at least, not as far as I can see). Is there any way to see exactly why SaveChanges threw an exception? At the very least, it would be helpful to see what table SaveChanges tried to update with when the error occured.

C# Solutions


Solution 1 - C#

This is my override of SaveChanges. It gives me a useful place to put breakpoints:

    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbEntityValidationException e)
        {
            foreach (var eve in e.EntityValidationErrors)
            {
                Debug.WriteLine(@"Entity of type ""{0}"" in state ""{1}"" 
                   has the following validation errors:",
                    eve.Entry.Entity.GetType().Name, 
                    eve.Entry.State);
                foreach (var ve in eve.ValidationErrors)
                {
                    Debug.WriteLine(@"- Property: ""{0}"", Error: ""{1}""",
                        ve.PropertyName, ve.ErrorMessage);
                }
            }
            throw;
        }
        catch(DbUpdateException e)
        {
           //Add your code to inspect the inner exception and/or
           //e.Entries here.
           //Or just use the debugger.
           //Added this catch (after the comments below) to make it more obvious 
           //how this code might help this specific problem
        }
        catch (Exception e)
        {
            Debug.WriteLine(e.Message);
            throw;
        }
    }

Reference:

https://stackoverflow.com/questions/7795300/validation-failed-for-one-or-more-entities-see-entityvalidationerrors-propert

Solution 2 - C#

Here's my override of SaveChanges, showing the additional code to deal with the DbUpdateException (as per the question).

    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbEntityValidationException vex)
        {
            var exception = HandleDbEntityValidationException(vex);
            throw exception;
        }
        catch(DbUpdateException dbu)
        {
            var exception = HandleDbUpdateException(dbu);
            throw exception;
        }
    }

    private Exception HandleDbUpdateException(DbUpdateException dbu)
    {
        var builder = new StringBuilder("A DbUpdateException was caught while saving changes. ");

        try
        {
            foreach (var result in dbu.Entries)
            {
                builder.AppendFormat("Type: {0} was part of the problem. ", result.Entity.GetType().Name);
            }
        }
        catch (Exception e)
        {
            builder.Append("Error parsing DbUpdateException: " + e.ToString());
        }

        string message = builder.ToString();
        return new Exception(message, dbu);
    }

I've not made the logging code very specific, but it improves on the standard error message of something like:

The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range value.

This way, at least I can see which entity has the problem, and that's normally enough to work it out.

Solution 3 - C#

Based on Colin's answer, fully detailed information on EF persistence failure can be provided like this:

public bool SaveChangesEx()
{
    try
    {
        SaveChanges();
        return true;
    }
    catch (DbEntityValidationException exc)
    {
        // just to ease debugging
        foreach (var error in exc.EntityValidationErrors)
        {
            foreach (var errorMsg in error.ValidationErrors)
            {
                // logging service based on NLog
                Logger.Log(LogLevel.Error, $"Error trying to save EF changes - {errorMsg.ErrorMessage}");
            }
        }

        throw;
    }
    catch (DbUpdateException e)
    {
        var sb = new StringBuilder();
        sb.AppendLine($"DbUpdateException error details - {e?.InnerException?.InnerException?.Message}");

        foreach (var eve in e.Entries)
        {
            sb.AppendLine($"Entity of type {eve.Entity.GetType().Name} in state {eve.State} could not be updated");
        }

        Logger.Log(LogLevel.Error, e, sb.ToString());

        throw;
    }
}

Beside validation errors, update exception will output both general error and context information.

Note: C# 6.0 is required for this code to work, as it uses null propagation and string interpolation.


For .NET Core the code is slightly changed since possible raised exceptions have a different structure / are populated differently:

    public void SaveChangesEx()
    {
        try
        {
            // this triggers defined validations such as required
            Context.Validate();
            // actual save of changes
            Context.SaveChangesInner();
        }
        catch (ValidationException exc)
        {
            Logger.LogError(exc, $"{nameof(SaveChanges)} validation exception: {exc?.Message}");
            throw;
        }
        catch (DbUpdateException exc)
        {
            Logger.LogError(exc, $"{nameof(SaveChanges)} db update error: {exc?.InnerException?.Message}");
            throw;
        }
        catch (Exception exc)
        {
            // should never reach here. If it does, handle the more specific exception
            Logger.LogError(exc, $"{nameof(SaveChanges)} generic error: {exc.Message}");
            throw;
        }
    }

The Context can be enhanced to automatically reject changes on failure, if the same context is not immediately disposed:

public void RejectChanges()
{
    foreach (var entry in ChangeTracker.Entries().Where(e => e.Entity != null).ToList())
    {
        switch (entry.State)
        {
            case EntityState.Modified:
            case EntityState.Deleted:
                entry.State = EntityState.Modified; //Revert changes made to deleted entity.
                entry.State = EntityState.Unchanged;
                break;
            case EntityState.Added:
                entry.State = EntityState.Detached;
                break;
        }
    }
}

public bool SaveChangesInner()
{
    try
    {
        SaveChanges();
        return true;
    }
    catch (Exception)
    {
        RejectChanges();
        throw;
    }
}

Solution 4 - C#

When it seems that the real exception gets lost somewhere, your best bet is to break on every exception. Regardless of if it's catched or swallowed somewhere, in or out your reach, the debugger will break and allow you to see what's going on.

See this MSDN link for more info:

How to: Break When an Exception is Thrown

Solution 5 - C#

I was having the same error "The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range value.\r\nThe statement has been terminated."

I put the Datetime value field like this Datetime.Now

var person = new Person
            {
               FirstName = "Sebastian",
               LastName = "Back",
               **BirthDate = DateTime.Now,**
               IsActive = true,
            };

Solution 6 - C#

I faced the same issue
If you are using SQL Server and you have parent and child tables with (FK) FOREIGN KEY,
make sure that the relationship among tables for example CASCADE on Delete or on Update.

Solution 7 - C#

I got same error and solve like that;

I have a field which data type is datetime and i aware that i am setting it without assigned datetime property. So i change it to "Datetime.Now" then i see problem was solved and it's been saved succesfuly

Solution 8 - C#

In my case i was using Stored Procedure to add an entity to DB. My SP is giving the runtime error due to which i was getting this error in C#. I corrected the SP and the EF worked perfectly. So if you are making use of SP to add,edit,delete or update in EF check if the corresponding sp is working correctly.

Solution 9 - C#

In my case, i there was created the table as DOMAIN\MyUser.TableName without noticing... Instead, I needed to recreate it as dbo.TableName.

My exception:

> {"ClassName":"System.Data.Entity.Infrastructure.DbUpdateException","Message":"An > error occurred while updating the entries. See the inner exception for > details.","Data":null,"InnerException":{"ClassName":"System.Data.Entity.Core.UpdateException","Message":"An > error occurred while updating the entries. See the inner exception for > details.","Data":null,"InnerException":{"Errors":[{"Source":".Net > SqlClient Data > Provider","Number":208,"State":1,"Class":16,"Server":"***","Message":"Invalid > object name > 'dbo.TableName'.","Procedure":"","LineNumber":1}],"ClientConnectionId":"ab3fcb89-392d-42a5-9548-19a8d0cf0cdb","ClassName":"System.Data.SqlClient.SqlException","Message":"Invalid > object name > 'dbo.TableName'.","Data":{"HelpLink.ProdName":"Microsoft SQL > Server","HelpLink.ProdVer":"15.00.2000","HelpLink.EvtSrc":"MSSQLServer","HelpLink.EvtID":"208","HelpLink.BaseHelpUrl":"http://go.microsoft.com/fwlink","HelpLink.LinkId":"20476"}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJohn ReynoldsView Question on Stackoverflow
Solution 1 - C#ColinView Answer on Stackoverflow
Solution 2 - C#a-hView Answer on Stackoverflow
Solution 3 - C#Alexei - check CodidactView Answer on Stackoverflow
Solution 4 - C#CronoView Answer on Stackoverflow
Solution 5 - C#Irving Saul QuirozView Answer on Stackoverflow
Solution 6 - C#issam al-namaniView Answer on Stackoverflow
Solution 7 - C#Taha KaracaView Answer on Stackoverflow
Solution 8 - C#yogihostingView Answer on Stackoverflow
Solution 9 - C#Henrique HoltzView Answer on Stackoverflow