DbEntityValidationException-오류의 원인을 쉽게 알 수있는 방법은 무엇입니까?
Entity Framework를 사용하는 프로젝트가 있습니다. SaveChanges
내 전화하는 동안 DbContext
다음 예외가 발생합니다.
System.Data.Entity.Validation.DbEntityValidationException : 하나 이상의 엔티티에 대한 유효성 검증에 실패했습니다. 자세한 내용은 'EntityValidationErrors'속성을 참조하십시오.
이것은 모두 훌륭하고 멋지지만이 예외가 발생할 때마다 디버거를 연결하고 싶지 않습니다. 또한 프로덕션 환경에서는 디버거를 쉽게 연결할 수 없으므로 이러한 오류를 재현하기 위해 많은 시간을 투자해야합니다.
안에 숨겨진 세부 정보를 어떻게 볼 수 DbEntityValidationException
있습니까?
가장 쉬운 해결책은 SaveChanges
엔터티 클래스 에서 재정의 하는 것입니다. 을 포착하고 DbEntityValidationException
실제 오류를 풀고 DbEntityValidationException
개선 된 메시지 로 새 메시지를 작성할 수 있습니다 .
- SomethingSomething.Context.cs 파일 옆에 부분 클래스를 작성하십시오.
- 이 게시물의 맨 아래에있는 코드를 사용하십시오.
- 그게 다야. 구현시 리팩터링 작업없이 재정의 된 SaveChanges를 자동으로 사용합니다.
예외 메시지는 이제 다음과 같습니다.
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/
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
컬렉션 을 보려면 다음 Watch 식을 Watch 창에 추가하십시오.
((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors
I'm using visual studio 2013
While you are in debug mode within the catch {...}
block open up the "QuickWatch" window (ctrl+alt+q) and paste in there:
((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.
For Visual 2012+ users who care only about the first error and might not have a catch
block, you can even do:
((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors.First().ValidationErrors.First().ErrorMessage
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
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
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.
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.
For Azure Functions we use this simple extension to 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);
}
Use try block in your code like
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
'Programing' 카테고리의 다른 글
strings.xml의 다른 문자열에서 하나의 문자열을 참조 하시겠습니까? (0) | 2020.04.27 |
---|---|
날짜 시간 열에서 날짜를 선택하는 방법은 무엇입니까? (0) | 2020.04.27 |
JavaScript를 사용하여 쉼표로 구분 된 문자열을 분할하는 방법은 무엇입니까? (0) | 2020.04.27 |
C ++ 함수에서 여러 값 반환 (0) | 2020.04.27 |
List에서 캐스트하기위한 더 짧은 구문 (0) | 2020.04.27 |