Поиск причины DBUpdateException
При вызове DbContext.SaveChanges
я получаю исключение DbUpdateException:
"В EntityFramework.dll появилось необработанное исключение типа" System.Data.Entity.Infrastructure.DbUpdateException ". Дополнительная информация: при обновлении записей произошла ошибка. Подробнее см. внутреннее исключение.
К сожалению, нет внутреннего исключения (по крайней мере, насколько я могу видеть). Есть ли способ узнать, почему именно SaveChanges
выбрасывает исключение? По крайней мере, было бы полезно увидеть, какая таблица SaveChanges пыталась обновить, когда произошла ошибка.
Ответы
Ответ 1
Когда кажется, что реальное исключение теряется где-то, лучше всего ломаться на каждое исключение. Независимо от того, поймал ли он или проглотил где-нибудь, вне или вне досягаемости, отладчик сломается и позволит вам увидеть, что происходит.
Для получения дополнительной информации см. эту ссылку MSDN:
Как разбить, когда выбрасывается исключение
Ответ 2
Это мое переопределение SaveChanges. Это дает мне полезное место для размещения контрольных точек:
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;
}
}
Ссылка:
Не удалось выполнить проверку для одного или нескольких объектов. Дополнительную информацию см. В разделе Свойство EntityValidationErrors
Ответ 3
Здесь мое переопределение SaveChanges, показывающее дополнительный код для обработки исключения DbUpdateException (в соответствии с вопросом).
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);
}
Я не сделал код регистрации очень конкретным, но он улучшает стандартное сообщение об ошибке:
The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range value.
Таким образом, по крайней мере, я вижу, какая у этого объекта проблема, и что обычно достаточно, чтобы ее решить.
Ответ 4
Основываясь на ответе Колина, можно получить полную подробную информацию об отказе персистентности EF следующим образом:
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;
}
}
Помимо ошибок проверки, исключение для обновления выводит как общую ошибку, так и контекстную информацию.
Примечание. Для работы этого кода требуется С# 6.0, так как он использует нулевое распространение и интерполяцию строк.
Ответ 5
У меня была такая же ошибка: "Преобразование типа данных datetime2 в тип данных datetime привела к внеурочному значению.\r\nПриложение завершено".
Я положил поле значения Datetime как это Datetime.Now
var person = new Person
{
FirstName = "Sebastian",
LastName = "Back",
**BirthDate = DateTime.Now,**
IsActive = true,
};
Ответ 6
Я получил ту же ошибку и решил вот так:
У меня есть поле, тип данных которого datetime, и я знаю, что устанавливаю его без назначенного свойства datetime. Поэтому я меняю его на " Datetime.Now", тогда я вижу, что проблема решена и она была сохранена succesfuly
Ответ 7
В моем случае я использовал Хранимую процедуру для добавления объекта в БД. Мой SP дает ошибку времени выполнения, из-за которой я получал эту ошибку в С#. Я исправил SP, и EF работал отлично.
Поэтому, если вы используете SP для добавления, редактирования, удаления или обновления в EF, проверьте, работает ли соответствующий sp.