DbEntityValidationException - как я могу легко сказать, что вызвало ошибку?
у меня есть проект, который использует Entity Framework. Во время вызова SaveChanges на DbContext, Я получаю следующее исключение:
система.Данные.Сущность.Утверждение.DbEntityValidationException: Проверка
ошибка для одного или нескольких объектов. См. свойство ' EntityValidationErrors
более подробный.
Это все прекрасно и денди, но я не хочу присоединять отладчик каждый раз, когда это исключение происходит. Более того, в производственных средах я не могу легко присоединить отладчик, так что я должен пойти на многое, чтобы воспроизвести эти ошибки.
как я могу увидеть детали, скрытые в DbEntityValidationException?
9 ответов:
самое простое решение-переопределить
SaveChangesна ваш класс сущностей. Вы можете пойматьDbEntityValidationException, разверните фактические ошибки и создайте новыйDbEntityValidationExceptionс улучшенным сообщением.
- создайте частичный класс рядом с вашим SomethingSomething.Контекст.cs-файл.
- использовать код в нижней части этого поста.
- вот и все. Ваша реализация будет автоматически использовать переопределить метод SaveChanges без каких-либо рефакторинг работы.
ваш сообщение об ошибке будет выглядеть так:
как указал Мартин, есть больше информации в
DbEntityValidationResult. Я счел полезным получить имя класса POCO и имя свойства в каждом сообщении и хотел избежать необходимости писать customErrorMessageатрибуты на все мои[Required]теги только для этого.следующая настройка кода Мартина позаботилась об этих деталях для меня:
// Retrieve the error messages as a list of strings. List<string> errorMessages = new List<string>(); foreach (DbEntityValidationResult validationResult in ex.EntityValidationErrors) { string entityName = validationResult.Entry.Entity.GetType().Name; foreach (DbValidationError error in validationResult.ValidationErrors) { errorMessages.Add(entityName + "." + error.PropertyName + ": " + error.ErrorMessage); } }
для просмотра
EntityValidationErrorscollection, добавьте в окно Watch следующее выражение Watch.((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrorsЯ использую visual studio 2013
пока вы находитесь в режиме отладки в
catch {...}блок откройте окно "QuickWatch" (ctrl+ alt+q) и вставить туда:((System.Data.Entity.Validation.DbEntityValidationException)ex).EntityValidationErrorsЭто позволит вам углубиться в
ValidationErrorsдерево. Это самый простой способ, который я нашел, чтобы получить мгновенное представление об этих ошибках.для пользователей Visual 2012+, которые заботятся только о первой ошибке и не может иметь
catchблок, вы даже можете сделать:((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors.First().ValidationErrors.First().ErrorMessage
чтобы быстро найти значимое сообщение об ошибке, проверяя ошибку во время отладки:
добавить быстрый часы для:
((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrorsдетализируйте EntityValidationErrors следующим образом:
(элемент коллекции, например, [0]) > ValidationErrors > (элемент коллекции, например, [0]) > сообщение об ошибке
на самом деле, это просто проблема проверки, EF сначала проверит свойства объекта, прежде чем вносить какие-либо изменения в базу данных. Таким образом, EF проверит, находится ли значение свойства вне диапазона, например, когда вы проектировали таблицу. Table_Column_UserName-это varchar (20). Но, в EF, вы ввели значение, которое больше, чем 20. Или, в других случаях, если столбец не позволяет быть нулевым. Таким образом, в процессе проверки вы должны установить значение в столбец not null, независимо от того, являетесь ли вы мы собираемся внести изменения в него. Я лично, как Leniel Macaferi ответа. Он может показать вам подробную информацию о проблемах проверки
Я думаю, что" фактические ошибки проверки " могут содержать конфиденциальную информацию, и это может быть причиной, по которой Microsoft решила поместить их в другое место (свойства). Решение отмеченных здесь является практичным, но его следует принимать с осторожностью.
Я бы предпочел создать метод расширения. Больше причин для этого:
- сохранить исходную трассировку стека
- следуйте принципу open / closed (т. е.: Я могу использовать разные сообщения для разных журналов)
- в производственных средах могут быть и другие места (т. е.: other dbcontext), где может быть брошено исключение DbEntityValidationException.
для функций Azure мы используем это простое расширение для Microsoft.Увеличение.Лесозаготовительный.ILogger
public static class LoggerExtensions { public static void Error(this ILogger logger, string message, Exception exception) { if (exception is DbEntityValidationException dbException) { message += "\nValidation Errors: "; foreach (var error in dbException.EntityValidationErrors.SelectMany(entity => entity.ValidationErrors)) { message += $"\n * Field name: {error.PropertyName}, Error message: {error.ErrorMessage}"; } } logger.LogError(default(EventId), exception, message); } }и пример использования:
try { do something with request and EF } catch (Exception e) { log.Error($"Failed to create customer due to an exception: {e.Message}", e); return await StringResponseUtil.CreateResponse(HttpStatusCode.InternalServerError, e.Message); }
используйте блок try в своем коде, например
try { // Your code... // Could also be before try if you know the exception occurs in SaveChanges context.SaveChanges(); } catch (DbEntityValidationException e) { foreach (var eve in e.EntityValidationErrors) { Console.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) { Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"", ve.PropertyName, ve.ErrorMessage); } } throw; }вы можете проверить детали здесь, а также
Comments