Ошибка проверки для одного или нескольких объектов при сохранении изменений в базе данных SQL Server с использованием Entity Framework

Я хочу сохранить свое Редактирование в базу данных, и я использую Entity FrameWork Code-First в ASP.NET MVC 3/С#, но я получаю ошибки. В моем классе Event у меня есть типы данных DateTime и TimeSpan, но в моей базе данных у меня есть дата и время соответственно. Может ли это быть причиной? Как я могу применить к соответствующему типу данных в коде перед сохранением изменений в базе данных.

public class Event
{
    public int EventId { get; set; }
    public int CategoryId { get; set; }
    public int PlaceId { get; set; }
    public string Title { get; set; }
    public decimal Price { get; set; }
    public DateTime EventDate { get; set; }
    public TimeSpan StartTime { get; set; }
    public TimeSpan EndTime { get; set; }
    public string Description { get; set; }
    public string EventPlaceUrl { get; set; }
    public Category Category { get; set; }
    public Place Place { get; set; }
}

Метод в контроллере → → Проблема в storeDB.SaveChanges();

// POST: /EventManager/Edit/386        
[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
    var theEvent = storeDB.Events.Find(id);

    if (TryUpdateModel(theEvent))
    {
        storeDB.SaveChanges();
        return RedirectToAction("Index");
    }
    else
    {
        ViewBag.Categories = storeDB.Categories.OrderBy(g => g.Name).ToList();
        ViewBag.Places = storeDB.Places.OrderBy(a => a.Name).ToList();
        return View(theEvent);
    }
}

с

public class EventCalendarEntities : DbContext
{
    public DbSet<Event> Events { get; set; }
    public DbSet<Category> Categories { get; set; }
    public DbSet<Place> Places { get; set; } 
}

SQL Server 2008 R2 База данных /T -SQL

EventDate (Datatype = date)  
StartTime (Datatype = time)  
EndTime (Datatype = time)  

Http Form

EventDate (Datatype = DateTime) e.g. 4/8/2011 12:00:00 AM  
StartTime (Datatype = Timespan/time not sure) e.g. 08:30:00  
EndTime (Datatype = Timespan/time not sure) e.g. 09:00:00  

Ошибка сервера в приложении "/".

Не удалось выполнить проверку для одного или нескольких объектов. Дополнительную информацию см. В разделе Свойство EntityValidationErrors.

Описание: Необработанное исключение возникло во время выполнения текущего веб-запроса. Просмотрите трассировку стека для получения дополнительной информации об ошибке и ее возникновении в коде.

Сведения об исключении: System.Data.Entity.Validation.DbEntityValidationException: сбой проверки для одного или нескольких объектов. Дополнительную информацию см. В разделе Свойство EntityValidationErrors.

Ошибка источника:

Line 75:             if (TryUpdateModel(theEvent))
Line 76:             {
Line 77:                 storeDB.SaveChanges();
Line 78:                 return RedirectToAction("Index");
Line 79:             }

Исходный файл: C:\sep\MvcEventCalendar\MvcEventCalendar\Controllers\EventManagerController.cs Строка: 77

Трассировка стека:

[DbEntityValidationException: сбой проверки для одного или нескольких объектов. Дополнительную информацию см. В разделе Свойство EntityValidationErrors.]

Ответ 1

Вы можете извлечь всю информацию из DbEntityValidationException с помощью следующего кода (вам нужно добавить пространства имен: System.Data.Entity.Validation и System.Diagnostics в список using):

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);
        }
    }
}

Ответ 2

Не требуется изменение кода:

Пока вы находитесь в режиме отладки в блоке catch {...}, откройте окно QuickWatch (Ctrl + Alt + Q) и вставьте туда:

((System.Data.Entity.Validation.DbEntityValidationException)ex).EntityValidationErrors

или

((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors

Если вы не находитесь в try/catch или не имеете доступа к объекту исключения.

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

Ответ 3

В случае, если у вас есть классы с одинаковыми именами свойств, вот небольшое расширение для ответа Правуэна:

 catch (DbEntityValidationException dbEx)
 {
    foreach (var validationErrors in dbEx.EntityValidationErrors)
    {
       foreach (var validationError in validationErrors.ValidationErrors)
       {
          Trace.TraceInformation(
                "Class: {0}, Property: {1}, Error: {2}",
                validationErrors.Entry.Entity.GetType().FullName,
                validationError.PropertyName,
                validationError.ErrorMessage);
       }
    }
 }

Ответ 4

В качестве улучшения как для Правэна, так и для Тони я использую переопределение:

public partial class MyDatabaseEntities : DbContext
{
    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbEntityValidationException dbEx)
        {
            foreach (var validationErrors in dbEx.EntityValidationErrors)
            {
                foreach (var validationError in validationErrors.ValidationErrors)
                {
                    Trace.TraceInformation("Class: {0}, Property: {1}, Error: {2}",
                        validationErrors.Entry.Entity.GetType().FullName,
                        validationError.PropertyName,
                        validationError.ErrorMessage);
                }
            }

            throw;  // You can also choose to handle the exception here...
        }
    }
}

Ответ 5

Я получал эту ошибку сегодня и не мог ее обработать некоторое время, но я понял, что это было после добавления некоторых моделей RequireAttribute к моим моделям и что некоторые данные семян разработки не заполняли все необходимые поля. < ш > Поэтому просто обратите внимание, что если вы получаете эту ошибку при обновлении базы данных с помощью какой-либо стратегии инициализации, такой как DropCreateDatabaseIfModelChanges, тогда вы должны убедиться, что ваши данные семени соответствуют и удовлетворяют любым атрибутам проверки данных модели.

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

Ответ 6

Я думаю, что добавление try/catch для каждой операции SaveChanges() не является хорошей практикой, лучше централизовать это:

Добавьте этот класс в основной класс 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.ErrorMessage));
        throw new DbEntityValidationException(errorMessages);
    }
}

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

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

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

Ответ 7

Этот код помог найти мою проблему, когда у меня возникла проблема с моей Entity VAlidation Erros. Он рассказал мне точную проблему с моим определением сущности. Попробуйте использовать следующий код, в котором вам нужно будет хранить storeDB.SaveChanges(); в следующем try catch catch.

  try
{
         if (TryUpdateModel(theEvent))
         {
             storeDB.SaveChanges();
             return RedirectToAction("Index");
         }
}
catch (System.Data.Entity.Validation.DbEntityValidationException dbEx)
{
    Exception raise = dbEx;
    foreach (var validationErrors in dbEx.EntityValidationErrors)
    {
        foreach (var validationError in validationErrors.ValidationErrors)
        {
            string message = string.Format("{0}:{1}", 
                validationErrors.Entry.Entity.ToString(),
                validationError.ErrorMessage);
            // raise a new exception nesting
            // the current instance as InnerException
            raise = new InvalidOperationException(message, raise);
        }
    }
    throw raise;
}

Ответ 8

Здесь расширение для расширения Тони...: -)

Для Entity Framework 4.x, если вы хотите получить имя и значение поля ключа, чтобы вы знали, какой экземпляр объекта (запись в базе данных) имеет проблему, вы можете добавить следующее. Это обеспечивает доступ к более мощным членам класса ObjectContext из вашего объекта DbContext.

// Get the key field name & value.
// This assumes your DbContext object is "_context", and that it is a single part key.
var e = ((IObjectContextAdapter)_context).ObjectContext.ObjectStateManager.GetObjectStateEntry(validationErrors.Entry.Entity);
string key = e.EntityKey.EntityKeyValues[0].Key;
string val = e.EntityKey.EntityKeyValues[0].Value;

Ответ 9

Мне не нравятся исключения Я зарегистрировал OnSaveChanges и получил это

var validationErrors = model.GetValidationErrors();

var h = validationErrors.SelectMany(x => x.ValidationErrors
                                          .Select(f => "Entity: " 
                                                      +(x.Entry.Entity) 
                                                      + " : " + f.PropertyName 
                                                      + "->" + f.ErrorMessage));

Ответ 10

Это исключение исключений для реализации исключений для исключения с подробным текстом. Он обрабатывает ошибки диапазона DbEntityValidationException, DbUpdateException, datetime2 (MS SQL) и включает в себя ключ недействительной сущности в сообщении (полезен, когда хранится много объектов при одном вызове SaveChanges).

Сначала переопределите SaveChanges в классе DbContext:

public class AppDbContext : DbContext
{
    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbEntityValidationException dbEntityValidationException)
        {
            throw ExceptionHelper.CreateFromEntityValidation(dbEntityValidationException);
        }
        catch (DbUpdateException dbUpdateException)
        {
            throw ExceptionHelper.CreateFromDbUpdateException(dbUpdateException);
        }
    }   

    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken)
    {
        try
        {
            return await base.SaveChangesAsync(cancellationToken);
        }
        catch (DbEntityValidationException dbEntityValidationException)
        {
            throw ExceptionHelper.CreateFromEntityValidation(dbEntityValidationException);
        }
        catch (DbUpdateException dbUpdateException)
        {
            throw ExceptionHelper.CreateFromDbUpdateException(dbUpdateException);
        }
    }

Класс ExceptionHelper:

public class ExceptionHelper
{
    public static Exception CreateFromEntityValidation(DbEntityValidationException ex)
    {
        return new Exception(GetDbEntityValidationMessage(ex), ex);
    }

    public static string GetDbEntityValidationMessage(DbEntityValidationException ex)
    {
        // Retrieve the error messages as a list of strings.
        var errorMessages = ex.EntityValidationErrors
            .SelectMany(x => x.ValidationErrors)
            .Select(x => x.ErrorMessage);

        // Join the list to a single string.
        var fullErrorMessage = string.Join("; ", errorMessages);

        // Combine the original exception message with the new one.
        var exceptionMessage = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage);
        return exceptionMessage;
    }

    public static IEnumerable<Exception> GetInners(Exception ex)
    {
        for (Exception e = ex; e != null; e = e.InnerException)
            yield return e;
    }

    public static Exception CreateFromDbUpdateException(DbUpdateException dbUpdateException)
    {
        var inner = GetInners(dbUpdateException).Last();
        string message = "";
        int i = 1;
        foreach (var entry in dbUpdateException.Entries)
        {
            var entry1 = entry;
            var obj = entry1.CurrentValues.ToObject();
            var type = obj.GetType();
            var propertyNames = entry1.CurrentValues.PropertyNames.Where(x => inner.Message.Contains(x)).ToList();
            // check MS SQL datetime2 error
            if (inner.Message.Contains("datetime2"))
            {
                var propertyNames2 = from x in type.GetProperties()
                                        where x.PropertyType == typeof(DateTime) ||
                                            x.PropertyType == typeof(DateTime?)
                                        select x.Name;
                propertyNames.AddRange(propertyNames2);
            }

            message += "Entry " + i++ + " " + type.Name + ": " + string.Join("; ", propertyNames.Select(x =>
                string.Format("'{0}' = '{1}'", x, entry1.CurrentValues[x])));
        }
        return new Exception(message, dbUpdateException);
    }
}

Ответ 11

Эта ошибка также возникает при попытке сохранить объект с ошибками проверки. Хороший способ вызвать это - забыть проверить ModelState.IsValid перед сохранением в вашей БД.

Ответ 12

Убедитесь, что если у вас есть nvarchar (50) в строке DB, вы не пытаетесь вставить в него более 50 символов. Глупая ошибка, но мне потребовалось 3 часа, чтобы понять это.

Ответ 13

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

Ответ 14

Thnaks за ваши ответы, это очень помогает мне. как я код в Vb.Net, этот код Болта для Vb.Net

Try
   Return MyBase.SaveChanges()
Catch dbEx As Validation.DbEntityValidationException
   For Each [error] In From validationErrors In dbEx.EntityValidationErrors
                       From validationError In validationErrors.ValidationErrors
                       Select New With { .PropertyName = validationError.PropertyName,
                                         .ErrorMessage = validationError.ErrorMessage,
                                         .ClassFullName = validationErrors.Entry.Entity
                                                                    .GetType().FullName}

        Diagnostics.Trace.TraceInformation("Class: {0}, Property: {1}, Error: {2}",
                                           [error].ClassFullName,
                                           [error].PropertyName,
                                           [error].ErrorMessage)
   Next
   Throw
End Try

Ответ 15

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

Ответ 16

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