使用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, 已補上鳥龍細節,感謝你的回饋。

Post a comment