C# DbEntityValidationException - 如何轻松判断导致错误的原因?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15820505/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
DbEntityValidationException - How can I easily tell what caused the error?
提问by Martin Devillers
I have a project that uses Entity Framework. While calling SaveChanges
on my DbContext
, I get the following exception:
我有一个使用实体框架的项目。在调用SaveChanges
my 时DbContext
,我收到以下异常:
System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
System.Data.Entity.Validation.DbEntityValidationException:一个或多个实体的验证失败。有关更多详细信息,请参阅“EntityValidationErrors”属性。
This is all fine and dandy, but I don't want to attach a debugger every time this exception occurs. More over, in production environments I cannot easily attach a debugger so I have to go to great lengths to reproduce these errors.
这一切都很好,但我不想每次发生此异常时都附加调试器。此外,在生产环境中,我无法轻松附加调试器,因此我必须竭尽全力重现这些错误。
How can I see the details hidden within the DbEntityValidationException
?
我怎样才能看到隐藏在里面的细节DbEntityValidationException
?
采纳答案by Martin Devillers
The easiest solution is to override SaveChanges
on your entities class. You can catch the DbEntityValidationException
, unwrap the actual errors and create a new DbEntityValidationException
with the improved message.
最简单的解决方案是覆盖SaveChanges
您的实体类。您可以捕获DbEntityValidationException
,解开实际错误并DbEntityValidationException
使用改进的消息创建新的。
- Create a partial class next to your SomethingSomething.Context.cs file.
- Use the code at the bottom of this post.
- That's it. Your implementation will automatically use the overriden SaveChanges without any refactor work.
- 在SomethingSomething.Context.cs 文件旁边创建一个分部类。
- 使用本文底部的代码。
- 就是这样。您的实现将自动使用覆盖的 SaveChanges,无需任何重构工作。
Your exception message will now look like this:
您的异常消息现在将如下所示:
System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. The validation errors are: The field PhoneNumber must be a string or array type with a maximum length of '12'; The LastName field is required.
System.Data.Entity.Validation.DbEntityValidationException:一个或多个实体的验证失败。有关更多详细信息,请参阅“EntityValidationErrors”属性。验证错误是: 字段 PhoneNumber 必须是最大长度为 '12' 的字符串或数组类型;姓氏字段是必需的。
You can drop the overridden SaveChanges in any class that inherits from DbContext
:
您可以在继承自 的任何类中删除覆盖的 SaveChanges DbContext
:
public partial class SomethingSomethingEntities
{
public override int SaveChanges()
{
try
{
return base.SaveChanges();
}
catch (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);
? ??
// Throw a new DbEntityValidationException with the improved exception message.
throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors);
}
}
}
The DbEntityValidationException
also contains the entities that caused the validation errors. So if you require even more information, you can change the above code to output information about these entities.
该DbEntityValidationException
还包含导致验证错误的实体。因此,如果您需要更多信息,您可以更改上述代码以输出有关这些实体的信息。
See also: http://devillers.nl/improving-dbentityvalidationexception/
另见:http: //devillers.nl/improving-dbentityvalidationexception/
回答by Eric Hirst
As Martin indicated, there is more information in the DbEntityValidationResult
. I found it useful to get both my POCO class name and property name in each message, and wanted to avoid having to write custom ErrorMessage
attributes on all my [Required]
tags just for this.
正如 Martin 所指出的,DbEntityValidationResult
. 我发现在每条消息中同时获取我的 POCO 类名和属性名很有用,并希望避免为此ErrorMessage
在我的所有[Required]
标签上编写自定义属性。
The following tweak to Martin's code took care of these details for me:
以下对 Martin 代码的调整为我处理了这些细节:
// 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);
}
}
回答by Atta H.
Use try block in your code like
在您的代码中使用 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;
}
You can check the details here as well
您也可以在此处查看详细信息
回答by Shehab Fawzy
To view the EntityValidationErrors
collection, add the following Watch expression to the Watch window.
要查看EntityValidationErrors
集合,请将以下 Watch 表达式添加到 Watch 窗口。
((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors
I'm using visual studio 2013
我正在使用 Visual Studio 2013
回答by Luis Toapanta
I think "The actual validation errors" may contain sensitive information, and this could be the reason why Microsoft chose to put them in another place (properties). The solution marked here is practical, but it should be taken with caution.
我认为“实际验证错误”可能包含敏感信息,这可能是 Microsoft 选择将它们放在另一个地方(属性)的原因。此处标记的解决方案是实用的,但应谨慎使用。
I would prefer to create an extension method. More reasons to this:
我更愿意创建一个扩展方法。更多原因:
- Keep original stack trace
- Follow open/closed principle (ie.: I can use different messages for different kind of logs)
- In production environments there could be other places (ie.: other dbcontext) where a DbEntityValidationException could be thrown.
- 保留原始堆栈跟踪
- 遵循开放/封闭原则(即:我可以为不同类型的日志使用不同的消息)
- 在生产环境中,可能有其他地方(即:其他 dbcontext)可以抛出 DbEntityValidationException。
回答by GONeale
While you are in debug mode within the catch {...}
block open up the "QuickWatch" window (ctrl+alt+q) and paste in there:
当您在catch {...}
块中处于调试模式时,打开“QuickWatch”窗口(ctrl+ alt+ q)并粘贴到那里:
((System.Data.Entity.Validation.DbEntityValidationException)ex).EntityValidationErrors
This will allow you to drill down into the ValidationErrors
tree. It's the easiest way I've found to get instant insight into these errors.
这将允许您深入到ValidationErrors
树中。这是我发现的立即洞察这些错误的最简单方法。
For Visual 2012+ users who care only about the first error and might not have a catch
block, you can even do:
对于只关心第一个错误并且可能没有catch
块的Visual 2012+ 用户,您甚至可以这样做:
((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors.First().ValidationErrors.First().ErrorMessage
回答by Chris Halcrow
To quickly find a meaningful error message by inspecting the error during debugging:
通过在调试期间检查错误来快速找到有意义的错误消息:
Add a quick watch for:
((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors
Drill down into EntityValidationErrors like this:
(collection item e.g. [0]) > ValidationErrors > (collection item e.g. [0]) > ErrorMessage
添加快速监视:
((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors
像这样深入到 EntityValidationErrors:
(集合项例如 [0]) > ValidationErrors > (集合项例如 [0]) > ErrorMessage
回答by Calvin
Actually, this is just the validation issue, EF will validate the entity properties first before making any changes to the database. So, EF will check whether the property's value is out of range, like when you designed the table. Table_Column_UserName is varchar(20). But, in EF, you entered a value that longer than 20. Or, in other cases, if the column does not allow to be a Null. So, in the validation process, you have to set a value to the not null column, no matter whether you are going to make the change on it. I personally, like the Leniel Macaferi answer. It can show you the detail of the validation issues
实际上,这只是验证问题,EF 会在对数据库进行任何更改之前先验证实体属性。因此,EF 将检查属性的值是否超出范围,就像您设计表格时一样。Table_Column_UserName 是 varchar(20)。但是,在 EF 中,您输入了一个超过 20 的值。或者,在其他情况下,如果该列不允许为 Null。因此,在验证过程中,您必须为非空列设置一个值,无论您是否要对其进行更改。我个人喜欢 Leniel Macaferi 的回答。它可以向您显示验证问题的详细信息
回答by Juri
For Azure Functions we use this simple extension to Microsoft.Extensions.Logging.ILogger
对于 Azure 函数,我们使用这个简单的Microsoft.Extensions.Logging.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);
}
}
and example usage:
和示例用法:
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);
}