Answers:
最简单的解决方案是SaveChanges
在实体类上重写。您可以捕获DbEntityValidationException
,解开实际的错误并DbEntityValidationException
使用改进后的消息创建新的错误。
您的异常消息现在将如下所示:
System.Data.Entity.Validation.DbEntityValidationException:对一个或多个实体的验证失败。有关更多详细信息,请参见'EntityValidationErrors'属性。验证错误是:字段PhoneNumber必须是最大长度为'12'的字符串或数组类型;姓氏字段是必填字段。
您可以将重写的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);
}
}
}
该DbEntityValidationException
还包含导致验证错误的实体。因此,如果您需要更多信息,则可以更改上面的代码以输出有关这些实体的信息。
另请参阅:http : //devillers.nl/improving-dbentityvalidationexception/
using System.Linq;
正如Martin所指出的,中有更多信息DbEntityValidationResult
。我发现在每条消息中同时获取POCO类名和属性名很有用,并希望避免为此而ErrorMessage
在所有[Required]
标签上编写自定义属性。
以下对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);
}
}
要查看EntityValidationErrors
集合,请在“监视”窗口中添加以下“监视”表达式。
((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors
我正在使用Visual Studio 2013
在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
我认为“实际的验证错误”可能包含敏感信息,这可能就是Microsoft选择将其放置在其他位置(属性)的原因。此处标记的解决方案是可行的,但应谨慎使用。
我希望创建一个扩展方法。这样做的更多原因:
对于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);
}
}
和示例用法:
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);
}
在代码中使用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;
}
您也可以在这里查看详细信息