使用实体框架将更改保存到SQL Server数据库时,一个或多个实体验证失败

我想保存我的编辑到数据库,我使用实体框架代码-在ASP。NET MVC 3 / c#,但我得到错误。在我的事件类中,我有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数据库

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

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

“/”应用程序中的服务器错误。

一个或多个实体验证失败。更多细节请参见'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:             }

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

堆栈跟踪:

[DbEntityValidationException:一个或多个实体验证失败。]更多细节请参见'EntityValidationErrors'属性。]

322406 次浏览

你可以用下面的代码从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);
}
}
}

无需更改代码:

当你在catch {...}块中处于调试模式时,打开“QuickWatch”窗口(Ctrl+Alt+)并粘贴在那里:

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

或者:

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

如果您不在try/catch中,或者没有访问异常对象的权限。

这将允许你深入到ValidationErrors树。这是我发现的最简单的方法来立即洞察这些错误。

在这种情况下,你有类具有相同的属性名,这是一个小扩展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);
}
}
}

这是托尼分机的分机…: -)

实体框架4。x,如果您想获得关键字段的名称和值,以便您知道哪个实体实例(DB记录)有问题,您可以添加以下内容。这提供了从DbContext对象访问更强大的ObjectContext类成员。

// 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;
我不喜欢异常 我注册了OnSaveChanges,并有这个

var validationErrors = model.GetValidationErrors();


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

作为对普拉文和托尼的改进,我使用了一个覆盖:

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...
}
}
}

我今天得到这个错误,暂时无法解决,但我意识到这是在向我的模型添加了一些__abc0之后,一些开发种子数据没有填充所有必需的字段 所以需要注意的是,如果你在通过诸如DropCreateDatabaseIfModelChanges之类的初始化策略更新数据库时得到这个错误,那么你必须确保你的种子数据满足并满足任何模型数据验证属性.

. 我知道这与问题中的问题略有不同,但这是一个很受欢迎的问题,所以我想我应该为和我有同样问题的其他人添加更多的答案 希望这对其他人有所帮助:)

谢谢你的回答,这对我帮助很大。 作为我的代码在Vb。Net,这个Vb的Bolt代码。净< / p >
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

当您试图保存具有验证错误的实体时,也会发生此错误。造成这种情况的一个好方法是忘记检查ModelState。在保存到您的DB之前是有效的。

确保如果你在DB行中有nvarchar(50),你不会试图插入超过50个字符。愚蠢的错误,但我花了3个小时才弄明白。

我认为为每个SaveChanges()操作添加try/catch并不是一个好的实践,最好集中如下:

将这个类添加到主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()方法,你将得到一个逗号分隔的列表,其中包含所有实体验证错误。

这也可以改进,在生产环境中记录错误,而不仅仅是抛出错误。

希望这对你有帮助。

这段代码帮助我找到我的问题,当我有实体验证错误的问题。它告诉我实体定义的确切问题。 尝试下面的代码,你需要覆盖storeDB.SaveChanges();在接下来的尝试捕获块。< / p >
  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;
}

它可能是由模型未填充的属性引起的。取而代之的是由Controller..这可能会导致这个错误..解决方案是在应用ModelState验证之前分配属性。 第二个假设是。您的数据库中可能已经有数据 尝试更新它,但现在取回它。< / p >

这可能是由于一个特定列允许的最大字符数,就像在sql中,一个字段可能在数据类型nvarchar(5)之后,但用户输入的字符数超过了指定的字符数,因此出现错误。

这个实现用详细文本将实体异常包装到异常。 它处理DbEntityValidationExceptionDbUpdateExceptiondatetime2范围错误(MS SQL),并在消息中包括无效实体的键(在一次SaveChanges调用中保存多个实体时很有用)

首先,在DbContext类中重写SaveChanges:

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

几天前我在更新数据库时遇到了同样的问题。在我的例子中,为维护添加了一些新的非空列,这在导致异常的代码中没有提供。我计算出这些字段并为它们提供值,然后解析。

在我的情况下,我有一个表列名称路径,我设置的数据类型是varchar(200)。更新到nvarchar(max)后,我从edmx中删除了表,然后再次添加了表,它对我来说工作正常。