2009-06-24 8 views
8

Comment puis-je sérialiser l'objet de structure d'entité dans JavaScript Object (JSON)? J'ai essayé d'utiliser JSON.NET mais je reçois l'exception suivante lorsque j'essaie de le sérialiser.Serialize Entity Framework Object utilisant Json.Net

Exception: Newtonsoft.Json.JsonSerializationException, message = "boucle d'auto-référencement"

Hitesh

Répondre

7

On dirait que vous rencontrez le même problème général que le sérialiseur DataContract original, en ce qui concerne les références cycliques. Alors que les objets se référant les uns aux autres sont assez communs avec les graphes d'objets en mémoire, de telles références cycliques entraînent inévitablement des récursions infinies lorsqu'elles sont sérialisées si le sérialiseur ne le prend pas spécifiquement en compte. Il existe peu ou pas de normes établies pour traiter les références cycliques dans les formats de sérialisation communs non binaires (XML et JSON étant les deux les plus répandus.)

Microsoft a résolu le problème cyclique du sérialiseur DataContract dans .NET 3.5 SP1 en utilisant la sémantique de référence dans xml. À ma connaissance, il n'y a pas une telle chose pour JSON, ce qui pourrait expliquer pourquoi JSON.NET vous empêche de sérialiser votre graphe d'objet. Je voudrais m'assurer que vous avez seulement des références dans votre graphe d'objet qui sont navigables unidirectionnelles, plutôt que les deux (c'est-à-dire seulement de parent à enfant, pas d'enfant à parent.) Ces parent/enfant et enfant/parent sont les types les plus courants de références cycliques. Il se peut aussi qu'un enfant de niveau inférieur fasse finalement référence à la racine du graphique, provoquant la création d'un graphe cyclique indirect (qui tend cependant à être beaucoup moins commun que les boucles parent/enfant.)

vous éliminez toutes les références cycliques dans votre graphe d'objets, vous devriez pouvoir sérialiser.

+0

Merci pour votre réponse. Je ne voulais pas éliminer les références cycliques dans le graphe d'objets car je ne suis pas tout à fait sûr de savoir comment le faire et quelles seraient les implications de ce changement. Au lieu de cela, j'ai créé des objets simples simples et peuplé ces objets en utilisant des objets Entity Framework, puis en sérialisant les objets simples et cela fonctionne bien. – Hitesh

+4

D'une manière générale, c'est une bonne pratique de garder vos entités de domaine et vos DTO indépendants les uns des autres. Les entités dans leur état natif, riche et graphique constituent un excellent moyen de modéliser un domaine de problème métier et de résoudre des problèmes métier, mais elles ne se prêtent pas bien à l'orientation-service et à la sérialisation. Ma préférence personnelle est de garder mon domaine aussi riche et interrelié que possible afin qu'il modélise l'entreprise et fournisse des API de service indépendantes qui fournissent des DTO sérialisables individuels. – jrista

+0

Ce problème est plus important que les cycles dans les références provoquées par les propriétés de navigation bidirectionnelles. Qu'en est-il lorsque vous avez 10 objets qui référencent tous exactement le même objet dépendant? Quelle est la manière standard de sérialiser ce graphique sans dupliquer l'objet référencé 10 fois? Et par ce même jeton désérialisant correctement les données du côté client, en recréant une seule instance de l'objet référencé au lieu de 10 différentes? Des normes ou des modèles communs pour cela en utilisant JSON? – Marchy

4

J'ai eu ce problème et l'ai résolu en ajoutant le Newtonsoft.Json.JsonIgnoreAttribute à la propriété provoquant la boucle. Évidemment, cette propriété ne sera pas sérialisée. Pour résoudre ce problème, j'ai généralement l'ID de référence étranger et la classe étrangère dans mes entités. Je me rends compte que ce n'est pas intuitif (ou super grand OO), mais c'est la manière recommandée par Julia Lerman dans son livre Programming Entity Framework: Code First. J'ai trouvé qu'il aide à aplanir plusieurs problèmes avec Entity Framework.

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

Mise à jour: j'ai oublié de mentionner que je devais aussi désactiver les procurations sur le DbContext comme ceci:

dataContext.Configuration.ProxyCreationEnabled = false; 

Si vous écrivez le code pour un service (ce qui semble probable si vous sérialisation) , alors ce n'est probablement pas un problème, mais il y a des choses que vous perdez quand la création de proxy est désactivée. Voir ici: http://www.sellsbrothers.com/posts/Details/12665 pour plus de détails.

J'utilise le MS Web Api, donc je désactiver simplement la création de proxy lorsque je construis mon contrôleur:

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

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

Pour contourner cela, je converti mes entités à code à base POCO premier. Pour ce faire, faites un clic droit dans votre fenêtre edmx et sélectionnez:

Ajouter un élément de génération de code> onglet Code> EF POCO Entity Generator.

Notez que vous devrez peut-être l'installer avec nuget si vous ne le voyez pas.Cependant, à l'exécution, EF ajoute des classes de proxy à ces objets à des fins de suivi, mais ils ont tendance à perturber le processus de sérialisation. Pour éviter cela, nous pouvons simplement mettre ProxyCreationEnabled false comme suit:

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

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

Vous pouvez ensuite retourner en toute sécurité des données sérialisés JSON.NET en omettant la référence par défaut en boucle comme suit:

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