DbEntityValidationException - как я могу легко сказать, что вызвало ошибку?



у меня есть проект, который использует Entity Framework. Во время вызова SaveChanges на DbContext, Я получаю следующее исключение:




система.Данные.Сущность.Утверждение.DbEntityValidationException: Проверка
ошибка для одного или нескольких объектов. См. свойство ' EntityValidationErrors
более подробный.




Это все прекрасно и денди, но я не хочу присоединять отладчик каждый раз, когда это исключение происходит. Более того, в производственных средах я не могу легко присоединить отладчик, так что я должен пойти на многое, чтобы воспроизвести эти ошибки.



как я могу увидеть детали, скрытые в DbEntityValidationException?

551   9  

9 ответов:

самое простое решение-переопределить SaveChanges на ваш класс сущностей. Вы можете поймать DbEntityValidationException, разверните фактические ошибки и создайте новый DbEntityValidationException с улучшенным сообщением.

  1. создайте частичный класс рядом с вашим SomethingSomething.Контекст.cs-файл.
  2. использовать код в нижней части этого поста.
  3. вот и все. Ваша реализация будет автоматически использовать переопределить метод SaveChanges без каких-либо рефакторинг работы.

ваш сообщение об ошибке будет выглядеть так:

как указал Мартин, есть больше информации в DbEntityValidationResult. Я счел полезным получить имя класса POCO и имя свойства в каждом сообщении и хотел избежать необходимости писать custom ErrorMessage атрибуты на все мои [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);
    }
}

для просмотра EntityValidationErrors collection, добавьте в окно 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;
}

вы можете проверить детали здесь, а также

  1. http://mattrandle.me/viewing-entityvalidationerrors-in-visual-studio/

  2. ошибка проверки для одного или нескольких объектов. Дополнительные сведения см. В разделе свойство EntityValidationErrors подробности

  3. http://blogs.infosupport.com/improving-dbentityvalidationexception/

Comments

    Ничего не найдено.