La prévention StackOverflowException lors de la sérialisation objet Entity Framework graphique en Json
Je veux sérialiser un Entité Cadre De L'Autonomie Des Entités De Suivi intégralité de l'objet graphique (parents + enfants dans de nombreuses relations) en Json.
Pour la sérialisation-je utiliser ServiceStack.JsonSerializer.
C'est ainsi que ma base de données ressemble (pour des raisons de simplicité, j'ai laissé tomber tous les champs de pertinence):
Je chercher un profil complet du graphe de cette façon:
public Profile GetUserProfile(Guid userID)
{
using (var db = new AcmeEntities())
{
return db.Profiles.Include("ProfileImages").Single(p => p.UserId == userId);
}
}
Le problème, c'est que tenter de le sérialiser:
Profile profile = GetUserProfile(userId);
ServiceStack.JsonSerializer.SerializeToString(profile);
produit un StackOverflowException
.
Je crois que c'est parce que EF offre une infinie modèle de la vis de la sérialiseur. C'est, je peux techniquement appel: profile.ProfileImages[0].Profile.ProfileImages[0].Profile ...
et ainsi de suite.
Comment puis-je "aplatir" mon EF objet graphique ou autrement empêcher ServiceStack.JsonSerializer de débordement de pile situation?
Remarque: je ne veux pas de projet de mon objet dans un type anonyme (comme ces suggestions) parce que ce serait introduire une très longue et difficile à maintenir fragment de code).
OriginalL'auteur Ofer Zelig | 2012-02-05
Vous devez vous connecter pour publier un commentaire.
Vous avez des préoccupations opposées, le modèle EF est optimisé pour le stockage de votre modèle de données dans un SGBD, et pas pour la sérialisation - qui est de savoir quel rôle la séparation des Dto allaient jouer. Sinon, vos clients seront liées à votre Base de données où chaque changement sur votre modèle de données a le potentiel de briser votre service clients.
Avec cela dit, la bonne chose à faire serait de séparer les Dto que vous associez à ce qui définit la forme souhaitée (aka wireformat) que vous souhaitez que les modèles ressemblent à du monde extérieur.
ServiceStack.Commune intégré dans la cartographie des fonctions (c'est à dire TranslateTo/PopulateFrom) qui simplifie la cartographie des entités à des Otd et vice-versa. Voici un exemple montrant ce:
https://groups.google.com/d/msg/servicestack/BF-egdVm3M8/0DXLIeDoVJEJ
L'alternative est de décorer les champs que vous souhaitez pour sérialiser sur votre Modèle de Données avec [DataContract] /[DataMember] champs. Toutes les propriétés qui ne sont pas attribués à [DataMember] pas être sérialisé - donc vous l'utiliser pour masquer les références cycliques qui sont à l'origine de la StackOverflowException.
Le truc, c'est que tout en essayant d'isoler le problème, ou de trouver une solution, j'ai trouvé que même la création d'un "fait main" objet de Profil avec un enfant ProfileImage objet et la sérialisation avec ServiceStack.JsonSerializer, provoque une StackOverflowException, mais en utilisant le Système.Web.Script.La sérialisation.JavaScriptSerializer réussit effectivement. J'ai toujours le problème de la construction de ces objets manuellement (à remplir en EF et de rétablir le "nettoyeur" versions), mais il fonctionne...
Si seulement je pouvais vous donner une médaille pour la décoration. Résolu mon problème de marquage de classes d'entité comme [DataContract], et tout membre je veux sérialisé avec [DataMember]
OriginalL'auteur mythz
Pour le bien de mes collègues StackOverflowers que d'entrer dans cette question, je vais vous expliquer ce que j'ai finalement fait:
Dans le cas que j'ai décrit, vous devez utiliser la norme .NET sérialiseur (plutôt que ServiceStack):
System.Web.Script.Serialization.JavaScriptSerializer
. La raison en est que vous pouvez décorer les propriétés de navigation vous ne voulez pas le sérialiseur à gérer dans un[ScriptIgnore]
attribut.Par le chemin, vous pouvez toujours utiliser
ServiceStack.JsonSerializer
pour la désérialisation - il est plus rapide .NET et vous n'avez pas le StackOverflowException questions que j'ai posé cette question à propos de.L'autre problème est de savoir comment obtenir l'Autonomie des Entités de Suivi pour décorer pertinentes propriétés de navigation avec
[ScriptIgnore]
.J'ai donc édité le
.TT
fichier qui est venu avec ADO.NET l'Auto-Suivi de l'Entité de Modèle de Générateur et définir pour contenir[ScriptIgnore]
dans les lieux (si quelqu'un veux le code diff, écrivez-moi un commentaire). Certains disent que c'est une mauvaise pratique pour éditer ces "externe", et non pas destiné à être modifié des fichiers, mais diable - elle résout le problème, et c'est la seule façon de ne pas me forcer à re-architecte de tout mon application (utilisation POCOs à la place des entreprises d'état, l'utilisation des Otd pour tout, etc.)@mythz: je ne suis pas absolument d'accord avec votre argumenter sur l'utilisation des Otd - voir moi des commentaires à votre réponse. J'apprécie vraiment vos efforts énormes bâtiment ServiceStack (tous les modules!) et faire il gratuit et open-source. Je viens de vous encourageons à les deux cas [ScriptIgnore] attribut dans votre texte sérialiseurs ou venir avec un attribut de la vôtre. D'autre, même si l'on fait peut utilisation des Otd, ils ne peuvent pas ajouter des propriétés de navigation à partir d'un objet enfant dos à un parent d'un, car ils obtiendront une StackOverflowException.
Je ne marquez votre réponse comme "accepté" car après tout, il m'a aidé à trouver mon chemin dans ce numéro.
Au moment où j'ai commencé la construction de l'infrastructure de notre application, je voulais vraiment utiliser EF en raison de ses fortes racines, plutôt que d'essayer de Micro ORM cadres. Je ne fais pas un point si c'était la meilleure décision à l'époque, mais je l'ai pris. Et à ce moment, EF Code-Première n'était pas encore prêt. Changer maintenant POCO et/ou dans d'autres ORM va être une vraie douleur...
Note: c'est ok pour aller avec EF, (la plupart des .NET 🙂 - tout en soulignant qu'il ne veut pas faire la promotion de l'idéal des modèles pour la sérialisation. Vous trouverez très peu de sérialiseurs sera en mesure de le sérialiser comme prévu - sans beaucoup de massage.
OriginalL'auteur Ofer Zelig
Être sûr de se Détacher de l'entité de ObjectContext avant de Sérialisation.
J'ai aussi utilisé Newton JsonSerializer.
JsonConvert.SerializeObject(EntityObject, La Mise En Forme.En retrait, la nouvelle JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objets });
Prendre un essai avec cette librairie json pour la sérialisation, je n'a pas eu de succès avec la norme Sérialiseurs. Installer JSON.NET via NuGET et de créer de petites démo
ServiceStack a fait le travail pour moi. Merci.
OriginalL'auteur Minja