EntityFramework烏龍記-SaveChanges出現OriginalValues取值錯誤

使用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

歡迎推文分享:
Published 04 June 2016 07:27 AM 由 Jeffrey
Filed under:
Views: 7,079



意見

# ace said on 03 June, 2016 10:51 PM

可以包這個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;

           }

# Jeffrey said on 03 June, 2016 11:28 PM

to ace, 謝謝你的提醒,忽然發現我看到的錯誤訊息可能與我回傳Exception訊息的邏輯有關,已準備重啟調查,隨後更新。

# Jeffrey said on 04 June, 2016 08:45 AM

to ace, 已補上鳥龍細節,感謝你的回饋。

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<June 2016>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789
 
RSS
創用 CC 授權條款
【廣告】
twMVC
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication