2009-06-24 56 views
8

如何序列化實體框架對象爲JavaScript對象(JSON)?我嘗試使用JSON.NET,但當我嘗試序列化它時,出現以下異常。使用Json.Net序列化實體框架對象

例外:Newtonsoft.Json.JsonSerializationException,消息=「自參照循環」

亞太區首席技術官Matt

回答

7

這聽起來像您有與原始DataContract串行大致相同的問題,關於循環引用。雖然相互引用的對象與內存中的對象圖相當常見,但如果序列化程序沒有專門說明它,則此類循環引用在序列化時不可避免地會導致無限遞歸。在通用的非二進制序列化格式中處理循環引用的標準(如果有的話)很少(XML和JSON是最常見的兩種)。

Microsoft解決了.NET 3.5中DataContract序列化程序的循環問題SP1通過使用xml中的引用語義。據我所知,JSON不存在這種情況,這可能是JSON.NET妨礙你序列化對象圖的原因。

我會確保你的對象圖中只有引用是可單向導航的,而不是兩種方式(即僅從父到子,不從子到父)。那些父/子和子/父是循環引用的最常見類型。也可能是一個較低級的孩子最終引用圖的根,導致創建一個間接的循環圖(然而,這些往往不如父/子循環常見)。

一旦您可以消除對象圖中的任何循環引用,您應該能夠序列化。

+0

謝謝您的回答。我不想消除對象圖中的任何循環引用,因爲我不完全確定如何執行此操作,以及進行此更改會產生什麼影響。相反,我創建普通的簡單對象,並使用實體框架對象填充這些對象,然後序列化普通對象,它工作正常。 – Hitesh 2009-06-24 22:42:27

4

我有這個問題,並通過將Newtonsoft.Json.JsonIgnoreAttribute添加到導致該循環的屬性來解決它。顯然,該屬性不會被序列化。爲了解決這個問題,我通常會在我的實體中使用外部引用ID和外部類。我意識到這不是直觀的(或超級好的OO),但它是Julia Lerman在她的書「編程實體框架:代碼優先」中推薦的方式。我發現它有助於消除Entity Framework中的幾個問題。

public class SomeEntity 
{ 
     [JsonIgnore] 
     public ForeignEntity SomeForeignEntity {get;set;} 
     public Guid ForeignEntityId {get;set;} 
} 

更新:我忘了說我還需要上的DbContext禁用代理,像這樣:

dataContext.Configuration.ProxyCreationEnabled = false; 

如果你正在寫一個服務代碼(這似乎很可能,如果您序列化) ,那麼這可能不是問題,但是當代理創建被禁用時,你會失去一些東西。看到這裏:http://www.sellsbrothers.com/posts/Details/12665瞭解更多詳情。

我使用的MS網絡API,所以我只是禁用代理創作時,我建我的控制器:

public class MailingApiController : ApiController 
{ 
    public MailingApiController() 
    { 
     PreventDeepSerialization(); 
    } 

    private static void PreventDeepSerialization() 
    { 
     var dataContext = Injector.Get<IIntertwyneDbContext>(); 
     dataContext.Configuration.ProxyCreationEnabled = false; 
    } 
     .... 
1

爲了解決這個問題我將我的實體基於POCO的Code First。爲此,請在您的edmx窗口中右鍵單擊並選擇:

添加代碼生成項>代碼選項卡> EF POCO實體生成器。

請注意,如果您沒有看到它,您可能需要使用nuget安裝它。

但是,在運行時,EF會將代理類添加到這些對象用於跟蹤目的,但它們往往會搞亂序列化過程。爲了防止這種情況,我們可以簡單地設置ProxyCreationEnabled爲false如下:

var context = new YourEntities(); 
context.Configuration.ProxyCreationEnabled = false; 

var results = context.YourEntity.Take(100).ToList(); 

然後,您可以安全地通過省略默認參考循環如下返回JSON.NET串行數據:

return JsonConvert.SerializeObject(results, Formatting.Indented, 
    new jsonSerializerSettings { 
     ReferenceLoopHandling = ReferenceLoopHandling.Ignore 
    });