2010-01-08 3 views
8

Mon dépôt a List<Student>, List<Course> et List<Enrolment> où une inscription a Enrolment.Student et Enrolment.Course qui sont des références un des étudiants ou des cours dans les deux listes précédentes. Lorsque j'utilise XmlSerializer sur mon référentiel, il génère des données redondantes en sérialisant toutes les propriétés de chaque étudiant en List<Student> puis de nouveau pour chaque référence à ces mêmes élèves en List<Enrolment>. Je cherche une manière élégante de résoudre ceci.XmlSerializer .NET et plusieurs références au même objet

Après la désérialisation, je peux corriger les références en utilisant les valeurs d'ID dans les instances d'objet en double créées par la désérialisation, mais cela semble hackish.

Une méthode pour corriger la sortie redondante consiste à XmlIgnore Enrolment.Student et Enrolment.Course et créer deux autres propriétés pour la sérialisation - Enrolment.StudentID et Enrolment.CourseID. Toutefois, lors de la désérialisation, les références pour Enrolment.Student et Enrolment.Course ne peuvent pas être définies (AFAIK) car les résultats de la désérialisation de List<Student> et List<Course> ne sont pas disponibles. Une autre méthode que j'ai pensé est de sérialiser plus bas dans ma hiérarchie d'objets en faisant chacune de mes listes séparément et en contrôlant l'ordre de désérialisation - je préfère ne pas le faire.

Une autre méthode serait XmlIgnore List<Enrolment> et créer une classe d'assistance de sérialisation d'inscription qui initialise List<Enrolment> après la désérialisation de lui-même est terminée. Cela semble beaucoup d'effort.

Comment d'autres personnes sérialisent/désérialisent plusieurs références au même objet à l'aide de XmlSerializer?

Répondre

3

Oh les douleurs de sérialisation: -> ...

Il n'y a jamais une solution générique pour cela, je suppose que c'est pourquoi MS il dépouillé du cadre Silverlight. Je ne m'appuie jamais sur les mécanismes de sérialisation automatique de l'infrastructure .net.

Pour mes propres modèles et référentiels, je sais généralement ou je peux facilement déterminer par programme quelles propriétés sont des propriétés scalaires simples (nombres/chaînes/etc) et qui sont des liens vers d'autres objets (ainsi que les listes de ces propriétés).

Il y a essentiellement 2 scénarios:

1: Nous voulons sérialisation/transfert uniquement les informations d'objets plats. Dans ce cas, je transfère uniquement les ID respectifs pour les propriétés liées à d'autres objets. Le récepteur peut ensuite effectuer des requêtes ultérieures pour obtenir tous les autres objets dont il a besoin.

2: Nous souhaitons transférer autant d'informations que possible, c'est-à-dire un code XML imbriqué plus profond avec plusieurs niveaux, principalement pour certaines fonctionnalités de rapport affichant tout directement en utilisant simplement du CSS sur le XML. Dans ce cas, il est réellement souhaité que les objets qui sont identiques soient résolus plusieurs fois dans l'arborescence XML.

Parfois, j'ai besoin d'ajuster un peu le premier scénario afin d'éviter trop d'appels de requêtes, mais je m'entends très bien. C'est à dire. J'ai intégré dans notre base de code que nous pouvons spécifier quels objets supplémentaires nous voulons résoudre quand, et/ou il est configuré quelque part.

+0

Très rassurant - Étant nouveau à cela, j'ai supposé qu'il me manquait quelque chose. Puisque mon problème se rapporte à votre premier scénario, je suivrai votre suggestion de construire quelque chose dans la base de code pour ranger la désérialisation. Peut-être que je vais créer une IXmlFinalizeDeserialization qui peut être appelée sur tous mes objets, en suivant ceux dont la désérialisation est insuffisante et en corrigeant les références. –

2

Il n'existe aucune solution à ce problème à l'aide du XML Serializer. Il n'a pas de concept d'identité qu'il pourrait utiliser pour supprimer la duplication. Le mieux que vous puissiez faire est de sérialiser le pool d'objets séparément de leurs références. Vous pouvez ensuite recréer vos listes après la désérialisation. Par ailleurs, savez-vous que le XmlSerializer n'est pas spécifique à C#?

+0

Merci John - très succinct. J'ai supprimé C# de mes tags. –

2

Vous pouvez implémenter l'interface IXmlSerializable d'inscription et dans la méthode WriteXml générer XML des étudiants et bien sûr qui sera contient seulement les clés .: par exemple

<Student Id="5"/> 
<Course Id="6"/> 

et méthode ReadXml vous pouvez charger des références de cette situation. Vous devez également définir l'attribut XmlIgnore sur la propriété Student et Course.

+0

Le problème avec cette approche est que lors de ReadXml vous ne pouvez pas charger des références (AFAIK) à d'autres données également désérialisées car elle n'est pas disponible jusqu'à la fin de la désérialisation. Savez-vous quelque chose autour de cela? –

0

Comment ce son comme une solution:

  1. XMLIgnore de chaque référence secondaire c.-à-Enrolment.Student & Enrolment.Course
  2. créer une propriété pour chaque référence secondaire qui est utilisé pour linéariser/désérialiser une clé étrangère pour cette référence à la place - Préfixe avec XML_FK. par exemple XML_FK_Student & XML_FK_Course
  3. Créer une XML_FinalizeDeserialization méthode qui est appelée après désérialisation pour charger les références utilisant ces étrangères propriétés clés.
+1

Ne serait-ce pas bien si nous pouvions créer un attribut [XmlSecondary] que nous mettions en avant d'une référence qui oblige le XML_Serializer à inspecter la référence pour les champs préfixés avec [XMLPK] et ne les affiche que? Possible? –

+0

Tout à fait possible, mais vous devrez alors écrire votre propre sérialiseur pour reconnaître l'attribut, et je pense que vous ne voulez pas faire cela. –

Questions connexes