EntityFramework烏龍記-SaveChanges出現OriginalValues取值錯誤
3 |
使用Entity Framework新増資料,SaveChanges()時出現以下錯誤:
System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
於 System.Data.Entity.Internal.InternalContext.SaveChanges()
於 System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
於 System.Data.Entity.DbContext.SaveChanges()*** DbEntityValidationException.EntityValidationErrors ***
Failed to dump exception: Error getting value from 'OriginalValues' on 'System.Data.Entity.Infrastructure.DbEntityEntry'.
深入檢查發現,要寫入的資料表有個不允許NULL的VARCHAR欄位,為新増資料物件對應該欄位的字串屬性忘了給值(呈現null)引發,修正後錯誤消失。原因很單純問題不難解,只是錯誤訊息玄疑了點。有此經驗,下回看到DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. 別看 EntityValidationErrors 以免愈看愈花,仔細檢查有沒有欄位少給值、長度不符… 就對了。
感謝讀者ace提醒,本案是一起烏龍。上述錯誤訊息是由自製函數產生,其中"Failed to dump exception"已提示為印出輸出例外資訊時出錯,Error getting value from 'OriginalValues' 並非EntityValidationErrors內容,一時失察錯判問題來源,先向大家致歉,晚點再提供更多細節。
[2016-06-04更新]
檢查程式後,查出問題出在當初便宜行事,想用SerializeObject將EntityValidationErrors序列化填入Log,加上覺得短短幾行不致出錯,心存僥倖沒實測驗證,藏下一個EntityValidationErrors無法用Json.NET SerializeObject()的Bug,再遇上射茶包精神不集中鬧了笑話,請大家見諒。匯出錯誤訊息的程式片段如下:
sb.AppendLine("*** DbEntityValidationException.EntityValidationErrors ***");
try {
sb.AppendLine(JsonConvert.SerializeObject(ex.EntityValidationErrors));
}
catch (Exception jsonEx)
{
sb.AppendLine("Failed to dump exception: " + jsonEx.Message);
}
正確寫法應如ace的做法:
sb.AppendLine("*** DbEntityValidationException.EntityValidationErrors ***");
try {
sb.AppendLine(JsonConvert.SerializeObject(ex.EntityValidationErrors
.SelectMany(o => o.ValidationErrors)
.Select(o => o.ErrorMessage).ToArray()));
}
catch (Exception jsonEx)
{
sb.AppendLine("Failed to dump exception: " + jsonEx.Message);
}
寫法對了,錯誤訊息根本清楚到驚天地泣鬼神,當初搞得一頭霧水全怪自己豬頭:
DbEntityValidationException.EntityValidationErrors ***
["Blah 欄位是必要項。"]
記取教訓:
寫完不測必有報應 寫完不測必有報應 寫完不測必有報應
眼拙心粗夏夕夏景 眼拙心粗夏夕夏景 眼拙心粗夏夕夏景
請大家以我為誡。Orz
Comments
# by ace
可以包這個catch exception,錯誤訊息會更清楚 catch (DbEntityValidationException ex) { var entityError = ex.EntityValidationErrors.SelectMany(x => x.ValidationErrors).Select(x => x.ErrorMessage); var getFullMessage = string.Join("; ", entityError); var exceptionMessage = string.Concat(ex.Message, "errors are: ", getFullMessage); result.Message = exceptionMessage; }
# by Jeffrey
to ace, 謝謝你的提醒,忽然發現我看到的錯誤訊息可能與我回傳Exception訊息的邏輯有關,已準備重啟調查,隨後更新。
# by Jeffrey
to ace, 已補上鳥龍細節,感謝你的回饋。