Pregunta

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.

Cuando uso XmlSerializer en mi repositorio se da salida a los datos redundantes, ya que serializa todas las propiedades de cada estudiante en List<Student> luego de nuevo para cada referencia a esos mismos estudiantes en List<Enrolment>. Estoy buscando una manera 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 fijar la salida redundante es XmlIgnore Enrolment.Student y Enrolment.Course y crear dos propiedades más para serialización - Enrolment.StudentID y Enrolment.CourseID. Sin embargo durante la deserialización, las referencias para Enrolment.Student y Enrolment.Course no se podrán ajustar (AFAIK) ya que los resultados de 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 -. Yo prefiero no hacer esto

Otro método sería XmlIgnore List<Enrolment> y crear una clase de ayuda serialización de inscripción que inicializa List<Enrolment> después de la deserialización de por sí es completa. Esto parece como una gran cantidad de esfuerzo.

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

¿Fue útil?

Solución

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 baso en cualquier mecanismo de serialización automática de .NET Framework. Para mis propios modelos y repositorios, por lo general conocen o pueden fácilmente mediante programación determinar qué propiedades son simples queridos escalares (números / cuerdas / etc) y que son enlaces a otros objetos (así como los que son listas de cualquiera).

Existen básicamente 2 escenarios:

1: Queremos serializar / transferencia sólo la información plana de objetos. En ese caso, transferir sólo los identificadores respectivos para las propiedades que enlazan con otros objetos. El receptor puede entonces realizar consultas posteriores para obtener todos los demás objetos que necesitan.

2: Queremos transferir la mayor cantidad de información posible, es decir, XML anidada con varios niveles, sobre todo para algunas funciones se informa que muestre todo directamente usando simplemente un poco de CSS en el código XML. En ese caso, en realidad se desea que los objetos que son los mismos serán resueltos varias veces en el árbol XML.

A veces tengo que retocar el primer escenario un poco con el fin de evitar demasiadas llamadas de consulta posteriores, pero por lo general se llevan muy bien. Es decir. He incorporado en nuestra base de código que podemos especificar qué objetos adicionales queremos resolver cuándo y / o que está configurado en alguna parte.

Otros consejos

No hay una solución para este problema mediante el serializador XML. Que no tiene un concepto de identidad que podría utilizar 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 deserialización.

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

Puede aplicar IXmlSerializable interfaz de Inscripción y en el método WriteXml generar alumno y curso XML que será sólo contiene claves por ejemplo:.

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

y en el método ReadXml puede cargar las referencias de este. También debe establecer el atributo XmlIgnore a la propiedad del estudiante y Curso.

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

  1. XmlIgnore cada secundaria referencia es decir Enrolment.Student y Enrolment.Course
  2. crear una propiedad para cada secundaria de referencia que se utiliza para serializar / deserializar una clave externa para que en lugar de referencia - Prefijo con XML_FK. por ejemplo XML_FK_Student y XML_FK_Course
  3. Crear un método que es XML_FinalizeDeserialization llamada después de deserialización para cargar las referencias que utilizan los extranjeros propiedades clave.

Debe / Puede utilizar el seguimiento de referencia con el serializador DataContract:

//deserilaize:
using(MemoryStream memStmBack = new MemoryStream()) {
  var serializerForth = new DataContractSerializer(
    typeof(YourType),
    null,
    0x7FFF /*maxItemsInObjectGraph*/ ,
    false /*ignoreExtensionDataObject*/ ,
    true /*preserveObjectReferences*/ ,
    null /*dataContractSurrogate*/ );

  byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
  memStmBack.Write(data, 0, data.Length);
  memStmBack.Position = 0;
  var lsBack = (YourType) serializerForth.ReadObject(memStmBack);

}
//serialize...
using(MemoryStream memStm = new MemoryStream()) {
    var serializer = new DataContractSerializer(
      typeof(YourType),
      knownTypes,
      0x7FFF /*maxItemsInObjectGraph*/ ,
      false /*ignoreExtensionDataObject*/ ,
      true /*preserveObjectReferences*/ ,
      null /*dataContractSurrogate*/ );

    serializer.WriteObject(memStm, yourType);

    memStm.Seek(0, SeekOrigin.Begin);

    using(var streamReader = new StreamReader(memStm)) {
        result = streamReader.ReadToEnd();

O utilice

[Serializable]
[DataContract(IsReference = true)]
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top