使用Entity Framework保存对SQL Server数据库的更改时,一个或多个实体的验证失败

use*_*767 333 c# sql asp.net-mvc entity-framework code-first

我想保存我的编辑到数据库,我在ASP.NET MVC 3/C#中使用实体框架代码优先,但我收到错误.在我的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; }
}
Run Code Online (Sandbox Code Playgroud)

控制器中的方法>>>> 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

public class EventCalendarEntities : DbContext
{
    public DbSet<Event> Events { get; set; }
    public DbSet<Category> Categories { get; set; }
    public DbSet<Place> Places { get; set; } 
}
Run Code Online (Sandbox Code Playgroud)

SQL Server 2008 R2数据库/ T-SQL

EventDate (Datatype = date)  
StartTime (Datatype = time)  
EndTime (Datatype = time)  
Run Code Online (Sandbox Code Playgroud)

Http表格

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  
Run Code Online (Sandbox Code Playgroud)

'/'应用程序中的服务器错误.

一个或多个实体的验证失败.有关详细信息,请参阅"EntityValidationErrors"属性.

描述:执行当前Web请求期间发生未处理的异常.请查看堆栈跟踪以获取有关错误及其源自代码的位置的更多信息.

异常详细信息:System.Data.Entity.Validation.DbEntityValidationException:一个或多个实体的验证失败.有关详细信息,请参阅"EntityValidationErrors"属性.

来源错误:

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

源文件:C:\ sep\MvcEventCalendar\MvcEventCalendar\Controllers\EventManagerController.cs行:77

堆栈跟踪:

[DbEntityValidationException:一个或多个实体的验证失败.有关详细信息,请参阅"EntityValidationErrors"属性.

Pra*_*sad 838

您可以提取所有从信息DbEntityValidationException用下面的代码(你需要添加命名空间:System.Data.Entity.ValidationSystem.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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 通过解释实际可以看到跟踪输出的位置,可以改进答案. (8认同)
  • Trace输出可以在Output窗口中看到.单击顶部的Debug - > Windows - > Output (8认同)
  • 如果任何种子数据不完全满足模型属性规则(如"必需"),您也可能会收到此错误.我添加了一个更多信息的答案. (7认同)
  • 先生,赢了互联网. (2认同)

GON*_*ale 249

无需更改代码:

当您处于catch {...}块内的调试模式时,打开"QuickWatch"窗口(Ctrl+ Alt+ Q)并粘贴到那里:

((System.Data.Entity.Validation.DbEntityValidationException)ex).EntityValidationErrors
Run Code Online (Sandbox Code Playgroud)

要么:

((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors
Run Code Online (Sandbox Code Playgroud)

如果您不在try/catch中,或者无法访问异常对象.

这将允许您深入到ValidationErrors树中.这是我发现能够即时了解这些错误的最简单方法.

  • 每次我得到这个异常,我都会搜索错误,然后我来到这里(Google的第二个结果),我发现这篇文章,我在Debug> Watch面板中使用了第二个解决方案.做过几十次.谢谢GONeale. (7认同)
  • 你我的朋友是个天才,你帮我跟踪了我收到的ET错误,谢谢! (6认同)
  • 没问题:)但不是天才,只爱QuickWatch :) (4认同)
  • 刚刚为那些无法访问异常对象/变量的人更新了答案. (4认同)

Ton*_*ony 37

如果你有具有相同属性名称的类,这里是Praveen答案的一个小扩展:

 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);
       }
    }
 }
Run Code Online (Sandbox Code Playgroud)


Bol*_*der 22

作为对Praveen和Tony的改进,我使用了覆盖:

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...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Sel*_*Sel 6

此实现将实体异常包装到具有详细文本的异常.它处理DbEntityValidationException,DbUpdateException,datetime2范围错误(MS SQL),并且包括在消息无效实体的关键(有用的一个savind许多实体时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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Рах*_*ана 5

当我遇到Entity VAlidation Erros问题时,此代码帮助我找到了问题.它告诉我我的实体定义的确切问题.尝试使用以下代码来覆盖storeDB.SaveChanges(); 在下面尝试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;
}
Run Code Online (Sandbox Code Playgroud)