2010-01-08 10 views
8

Mi repositorio tiene List<Student>, List<Course> y List<Enrolment> donde una inscripción tiene Enrolment.Student y Enrolment.Course que son referencias uno de los estudiantes o cursos en las dos listas anteriores..NET XmlSerializer y múltiples referencias al mismo objeto

Cuando uso XmlSerializer en mi repositorio genera datos redundantes, ya que serializa todas las propiedades de cada alumno en List<Student>, luego de nuevo por cada referencia a esos mismos estudiantes en List<Enrolment>. Estoy buscando una forma elegante de resolver esto.

Después de deserialización puedo arreglar las referencias utilizando los valores de ID en las instancias de objetos duplicados creados por la deserialización pero esto parece hacker.

Un método para corregir la salida redundante es XmlIgnore Enrolment.Student y Enrolment.Course y crear dos propiedades más para la serialización: Enrolment.StudentID and Enrolment.CourseID. Sin embargo, durante la deserialización, no se pueden establecer las referencias para Enrolment.Student y Enrolment.Course (AFAIK) ya que los resultados de la deserialización de List<Student> y List<Course> no están disponibles.

Otro método pensé es serializar más abajo en mi jerarquía de objetos haciendo cada una de mis listas por separado y controlar el orden de deserialización - Prefiero no hacer esto.

Otro método sería crear XmlIgnore List<Enrolment> y crear una clase auxiliar de serialización de inscripción que inicialice List<Enrolment> después de que se complete la deserialización de sí mismo. Esto parece mucho esfuerzo.

¿Cómo otras personas serializar/deserializar múltiples referencias al mismo objeto usando XmlSerializer?

Respuesta

3

Oh los dolores de serialización: -> ...

nunca hubo una solución genérica para esto, supongo que por eso MS despojado fuera del marco de Silverlight.

Nunca confío en ningún mecanismo de serialización automática del .NET Framework. Para mis propios modelos y repositorios, generalmente sé o puedo determinar mediante programación de forma sencilla qué propiedades son simples escalares (números/cadenas/etc.) y cuáles son enlaces a otros objetos (así como cuáles son listas de cualquiera de ellos).

Hay básicamente 2 escenarios:

1: Queremos serializar/transferencia sólo la información plana de objetos. En ese caso, transfiero solo los respectivos ID para las propiedades que se vinculan a otros objetos. El receptor puede realizar consultas posteriores para obtener todos los demás objetos que necesita.

2: Queremos transferir tanta información como sea posible, es decir, XML anidado más profundo con varios niveles, sobre todo para algunas funciones de informes que muestran todo directamente utilizando simplemente algunos CSS en el XML. En ese caso, en realidad se desea que los objetos que sean iguales se resuelvan varias veces en el árbol XML.

A veces necesito modificar un poco el primer escenario para evitar demasiadas llamadas de consulta posteriores, pero normalmente me llevo muy bien. Es decir. He incorporado en nuestra base de código que podemos especificar qué objetos adicionales queremos resolver cuando, y/o está configurado en algún lugar.

+0

Muy tranquilizador. Siendo nuevo en esto, asumí que debía perderme algo. Dado que mi problema se relaciona con su primer escenario, seguiré su sugerencia de incorporar algo en la base de códigos para ordenar la deserialización. Tal vez crearé un IXmlFinalizeDeserialization que se puede invocar en todos mis objetos, rastreando aquellos cuya deserialización es inadecuada y corrige las referencias. –

2

No hay solución para este problema con el Serializador XML. No tiene un concepto de identidad que pueda usar para eliminar la duplicación.

Lo mejor que puede hacer es serializar el conjunto de objetos por separado de sus referencias. A continuación, puede volver a crear sus listas después de la deserialización.

Por cierto, ¿es consciente de que el XmlSerializer no es específico de C#?

+0

Gracias John - muy sucinto. Eliminé C# de mis etiquetas. –

2

Puede implementar IXmlSerializable interfaz de Inscripción y en el método WriteXml generar alumno y curso XML que será sólo contiene teclas ej .:

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

y en el método ReadXml que es posible cargar las referencias de este. También debe establecer el atributo XmlIgnore en las propiedades de Estudiante y Curso.

+0

El problema con este enfoque es que durante ReadXml no puede cargar referencias (AFAIK) a otros datos que también están deserializados porque no están disponibles hasta que finaliza la deserialización. ¿Sabes de alguna manera alrededor de esto? –

0

¿Cómo funciona este sonido como una solución:

  1. XmlIgnore cada secundaria referencia es decir Enrolment.Student & Enrolment.Course
  2. crear una propiedad para cada referencia secundaria que se utiliza para serialize/deserializar una clave foránea para esa referencia en su lugar - Prefijo con XML_FK. por ejemplo XML_FK_Student & XML_FK_Course
  3. Crear una XML_FinalizeDeserialization método que se llama después de deserialización para cargar las referencias utilizando esos propiedades clave extranjeros.
+1

¿No sería bueno si pudiésemos crear un atributo [XmlSecondary] que coloquemos antes de una referencia que haga que el XML_Serializer inspeccione la referencia de los campos con el prefijo [XMLPK] y solo los genere? ¿Posible? –

+0

Muy posible, pero necesitaría escribir su propio serializador para reconocer el atributo, y creo que no quiere hacer eso. –

Cuestiones relacionadas