Получение точного типа ошибки из DbValidationException

184

У меня есть ситуация, когда я инициализирую свою модель в DatabaseInitializer () для EF 4.1 и получаю эту досадную ошибку. "Validation failed for one or more entities. See 'EntityValidationErrors' property for more details."Итак, я перехожу к этому EntityValidationErrors, и есть поле, {System.Data.Entity.Validation.DbEntityValidationResult}которое вообще не дает мне никакой информации о том, какое поле не удалось инициализировать , Есть ли способ получить больше информации об этой ошибке?

Чтобы очистить вещи:

Я знаю, как исправить проблему длины строки. Я спрашиваю, как мне получить точное имя поля, которое нарушает модель.

Naz
источник

Ответы:

377

Пока вы находитесь в режиме отладки внутри 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
GONeale
источник
9
Это лучше, чем другой ответ :)
Даг
98
Если у вас нет блока catch, вы можете заменить exна $exceptionи получить тот же результат.
Ecyrb
Также убедитесь , что вы заменить exс ж / д ваш catch (Exception THIS)есть
Eonasdan
@Ecyrb, спасибо. Вы сэкономили часы поиска в Google. Кроме того, даже если счетчик ошибок валидации показан как 1, в массиве фактически есть два элемента с двумя ошибками.
матрица
3
Для тех, кто не ссылается на System.Linq и использует немедленное окно:System.Linq.Enumerable.ToList(System.Linq.Enumerable.ToList(((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors)[0].ValidationErrors)[0].ErrorMessage
jpsimard-nyx
124

Вы можете попробовать это в блоке try / catch?

catch (DbEntityValidationException dbEx)
{
    foreach (var validationErrors in dbEx.EntityValidationErrors)
    {
        foreach (var validationError in validationErrors.ValidationErrors)
        {
            Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
        }
    }
}
Трент Шолль
источник
11

Лучшее решение, на мой взгляд, это централизованно обрабатывать ошибки такого рода.

просто добавьте этот метод в основной DbContextкласс:

public override int SaveChanges()
{
    try
    {
        return base.SaveChanges();
    }
    catch (DbEntityValidationException ex)
    {
        string errorMessages = string.Join("; ", ex.EntityValidationErrors.SelectMany(x => x.ValidationErrors).Select(x => x.PropertyName + ": " + x.ErrorMessage));
        throw new DbEntityValidationException(errorMessages);
    }
}

Это перезапишет SaveChanges()метод вашего контекста, и вы получите список через запятую, содержащий все ошибки проверки сущности.

надеюсь, что это полезно.

Читиви Малек
источник
4

Ну, у меня была такая же проблема. Моя модель хорошо работала в EF CTP5, но не смогла встроить 4.1 с той же ошибкой "" Проверка не удалась для одной или нескольких сущностей ", когда я попытался ее инициализировать. Я выяснил, что у меня есть свойство:

public string Comment {get; set;}

Затем в методе seed в переопределенном инициализаторе у меня был довольно длинный (около 600 букв) комментарий.

Я думаю , что точка: в EF 4.1 вы должны аннотации набора данных в явном виде в некоторых случаях. Для меня настройка:

[StringLength(4000)] 
public string Comment {get; set;}

помог. Это странно, так как у CTP5 не было проблем с этим.

Войцех Котлински
источник
Хорошо, что я спрашивал, как я могу получить точное имя свойства, которое нарушает модель. Однако мне удалось преодолеть проблему, о которой вы говорили, используя [StringLength (Int32.MaxValue)] в качестве атрибута для моего свойства (как это было предложено Ладиславом Мрнкой, и я говорил об этом в этом вопросе stackoverflow.com/questions/5346155/… ) Powodzenia! =)
Наз
Это было брошено, когда я добавил новое свойство в мою модель в 4.1. Работал отлично в 4.1 раньше. Weird. Решается добавлением аннотации ко всем свойствам в модели.
Роберто Бонини
1

Я нашел полезным создать оболочку SaveChanges, которая делает EntityValidationErrors более читабельными:

Public Sub SaveChanges(entities As Entities)

    Try
        entities.SaveChanges()

    Catch ex As DbEntityValidationException

        Dim msg As New StringBuilder
        msg.AppendLine(ex.Message)

        For Each vr As DbEntityValidationResult In ex.EntityValidationErrors
            For Each ve As DbValidationError In vr.ValidationErrors
                msg.AppendLine(String.Format("{0}: {1}", ve.PropertyName, ve.ErrorMessage))
            Next
        Next

        Throw New DbEntityValidationException(msg.ToString, ex.EntityValidationErrors, ex)

    End Try

End Sub

а затем изменил «entity.SaveChanges ()» на «SaveChanges (entity)» во всем моем проекте

smirkingman
источник
0

Я знаю, что это старый вопрос, но вот мой ответ:

catch (DbEntityValidationException ex)
   {
    String.Join("\n", ex.EntityValidationErrors
          .SelectMany(x => x.ValidationErrors)
          .Select(x => x.ErrorMessage)
          .ToArray());
   }

и если вы сначала используете код, вы также можете глобализировать свои сообщения об ошибках, используя несколько файлов ресурсов

Например, у меня есть эти два отдельных файла ресурсов, один для ошибки и один для имени свойства, и я использую их следующим образом: введите описание изображения здесь введите описание изображения здесь

public class Person 
    {
        [Required(ErrorMessageResourceName = "required",ErrorMessageResourceType =typeof(ErrorMessages))]
        [MaxLength(100,ErrorMessageResourceName = "maxLength", ErrorMessageResourceType = typeof(ErrorMessages))]
        [Display(Name = "FirstName",ResourceType = typeof(Properties))]
        public string FirstName { get; set; }
         }

Как вы можете видеть, я полностью перевел свои сообщения об ошибках, включая имена свойств, чтобы потом я мог использовать их в пользователе, например:

введите описание изображения здесь

NikiUsefi
источник