2010-06-20 19 views
8

var store = GetStore(); usando (IsolatedStorageFileStream fileStream = store.OpenFile (RootData, FileMode.Create)) { DataContractSerializer serializer = new DataContractSerializer (typeof (List)); serializer.WriteObject (fileStream, rootdatalist); }serializar el objeto con los subelementos C#

Pero esto solo serializa el rootdatalist, y no los subelementos. El rootdatalist tiene una propiedad List de nodos, ¿cómo la serializo para que obtenga la jerarquía de la lista serializada?

Ya que está DBML objetos generados de la propiedad nodos de la raíz es

public System.Data.Linq.Table<Node> Nodes 
{ 
    get 
    { 
     return this.GetTable<Node>(); 
    } 
} 
retorno

Mi DataContext es:

public List<Root> GetRootList(Guid userid) 
{ 
    DataLoadOptions loadopts = new DataLoadOptions(); 
    loadopts.LoadWith<Root>(s => s.Nodes); 
    this.DataContext.LoadOptions = loadopts; 
    return this.DataContext.Root.Where(s => s.Nodes.Count(n => n.UserId == userid) > 0).ToList(); 
} 

la EntitySet Nodo se ve de la siguiente manera en mi diseñador dbml

[global::System.Data.Linq.Mapping.AssociationAttribute(Name="Root_Node", Storage="_Nodes", ThisKey="Id", OtherKey="RootId")] 
[global::System.Runtime.Serialization.DataMemberAttribute(Order=5, EmitDefaultValue=false)] 
public EntitySet<Node> Nodes 
{ 
    get 
    { 
     if ((this.serializing && (this._Nodes.HasLoadedOrAssignedValues == false))) 
     { 
      return null; 
     } 
     return this._Nodes; 
    } 
    set 
    { 
     this._Nodes.Assign(value); 
    } 
} 

También tengo que tener la etiqueta [Include] encima de mis propiedades o nada g se cargará. Editar :: Para otros que quieran serializar clases DBML http://blogs.msdn.com/b/wriju/archive/2007/11/27/linq-to-sql-enabling-dbml-file-for-wcf.aspx

+0

¿Hay alguna información [DataMember] arriba 'Nodos'? ¿Y qué es 'Root' aquí? El hecho de que expone una 'Tabla ' me hace pensar que es un 'DataContext', pero' DataContext' no es (AFAIK) destinado a ser parte del modelo serializable: es más el administrador que un objeto de dominio. (Una relación regular de un tipo generado por dbml unidireccional sería 'EntitySet ', no 'Tabla ') –

+0

Es definitivamente parte de un contexto de datos, pero pensé que el objeto sería serializable cuando agregué la serialización unidireccional de acuerdo con el enlace inferior de mi publicación. Desafortunadamente no parece así. No estoy del todo seguro de lo que estoy haciendo mal – Jakob

+0

@Jakob - exactamente; el * data-context * no está diseñado para ser serializable. Solo sus * entidades de dominio * se vuelven serializables. Sin embargo; ¿Cuál es tu objetivo aquí? Puede que tenga más que unos pocos trucos en la manga ... (humildemente presento que estoy * dolorosamente * familiarizado con la serialización de .NET en múltiples formas) –

Respuesta

9

¿Puede incluir más información sobre los tipos de contrato? Me esperar, por ejemplo, que Root se marca como un contrato de datos, con el miembro como un miembro de datos, por ejemplo:

[DataContract] 
public class Root { 
    [DataMember] 
    public List<SubItem> Nodes {get;private set;} 
} 

[DataContract] 
public class SubItem { 
    [DataMember] 
    public int Foo {get;set;} 

    [DataMember] 
    public string Bar {get;set;} 
} 

Eso entonces debería funcionar. Si no, realmente sería útil ver sus tipos (o una versión reducida de ellos, que ilustra el problema).

7

Los DataContractSerializer necesita saber acerca de todos los de los tipos en su gráfico de objetos.

Uso del constructor overload que le permite especificar los, así como el tipo raíz:

DataContractSerializer serializer = new DataContractSerializer(typeof(List<Root>), listOfOtherTypes); 
+0

¿Esto también funcionará si la Lista es realmente EntityRef en la clase Root? – Jakob

+0

@Jakob - Debería, siempre y cuando le cuente al serializador sobre el tipo. Vea la respuesta de Marc también, ya que también necesita especificar sus 'DataContract's y' DataMember's correctamente. – Oded

+0

dado que esto se genera, los contratos deberían ser correctos. Y en los escenarios * most *, ** ** es necesario proporcionar datos adicionales al ctor. En particular, la herencia se puede tratar a través de '[KnownType]' etc. –

0

OK; He tenido otra oportunidad de reproducir esto, usando las tablas Person/PersonPhone (en el esquema Person) de una nueva instalación de AdventureWorks2008R2.

Tengo el contexto de datos configurado para la serialización "Unidireccional", con enlaces LINQ-a-SQL estándar, etc. (sin personalizaciones). Para compararlo con tu escenario, un Person puede tener PersonPhone s, y estamos interesados ​​en una List<Person>.He mirado en 3 escenarios, cada uno mirando el conjunto completo de datos:

  1. serialización de un conjunto de vainilla de Person registros
  2. lo mismo que 1, pero utilizando LoadWith para obtener los registros telefónicos
  3. la igual que 1, pero iterando manualmente los datos (nota: esto puede causar problemas N + 1)

Aquí están los resultados; como puede ver, 1 falla en la forma en que describe, pero 2 & 3 funcionan bien, con la distinción de que 3 hace significativamente más trabajo TSQL.

Así sin más detalles (lo ideal sería un ejemplo totalmente reproducible), es muy difíciles de investigar más a fondo ...

Resultados: Plataforma

Default 
======= 
Bytes: 20219898 
Original person count: 19972 
Original phone count: 0 
Deser person count: 19972 
Deser phone count: 0 
Log: 1140 

LoadWith 
======== 
Bytes: 24767996 
Original person count: 19972 
Original phone count: 19972 
Deser person count: 19972 
Deser phone count: 19972 
Log: 2517 

Enumerated 
========== 
Bytes: 24767996 
Original person count: 19972 
Original phone count: 19972 
Deser person count: 19972 
Deser phone count: 19972 
Log: 6322697 

Prueba:

class Program 
{ 

    static void Main(string[] args) 
    { 
     using(var dc = new DataClasses1DataContext()) 
     { // 1: vanilla 
      dc.Log = new StringWriter(); 
      RoundtripAndCount("Default", dc.Persons); 
      Console.WriteLine("Log: " + dc.Log.ToString().Length); 
     } 
     using (var dc = new DataClasses1DataContext()) 
     { // 2: LoadWith 
      dc.Log = new StringWriter(); 
      var opt = new DataLoadOptions(); 
      opt.LoadWith<Person>(p => p.PersonPhones); 
      dc.LoadOptions = opt; 
      RoundtripAndCount("LoadWith", dc.Persons); 
      Console.WriteLine("Log: " + dc.Log.ToString().Length); 
     } 
     using (var dc = new DataClasses1DataContext()) 
     { // 3: iterate manually 
      dc.Log = new StringWriter(); 
      // manually iterate the data (LINQ-to-Objects) 
      GC.KeepAlive(dc.Persons.AsEnumerable().Sum(p=>p.PersonPhones.Count())); // just an opaque method 
      RoundtripAndCount("Enumerated", dc.Persons); 
      Console.WriteLine("Log: " + dc.Log.ToString().Length); 
     } 
    } 

    static void RoundtripAndCount(string caption, IEnumerable<Person> people) 
    { 
     Console.WriteLine(); 
     Console.WriteLine(caption); 
     Console.WriteLine(new string('=', caption.Length)); 
     List<Person> list = people.ToList(), clone; 
     using(var ms = new MemoryStream()) 
     { 
      var ser = new DataContractSerializer(typeof (List<Person>)); 
      ser.WriteObject(ms, list); 
      ms.Position = 0; 
      clone = (List<Person>) ser.ReadObject(ms); 
      Console.WriteLine("Bytes: " + ms.Length); 
     } 
     Func<Person, int> phoneCount = p => p.PersonPhones.HasLoadedOrAssignedValues ? p.PersonPhones.Count() : 0; 
     Console.WriteLine("Original person count: " + people.Count()); 
     Console.WriteLine("Original phone count: " + people.Sum(phoneCount)); 

     Console.WriteLine("Deser person count: " + clone.Count()); 
     Console.WriteLine("Deser phone count: " + clone.Sum(phoneCount)); 

    } 
} 

Como nota al margen, I podría modifica protobuf-net para convencer a L2S de que le proporcione los datos (donde DataContractSerializer decide ignorarlo), pero esto reproduce el escenario 3 con un enorme costo de N + 1. En consecuencia, no estoy planeando buscar eso ...

+0

@Marc - ¿le gustaría tener una vista compartida con ms teamviewer, o algo así? – Jakob

+0

@Marc: ¿hay alguna etiqueta [incluir] en los metadatos? Tengo que tener esos en mi proyecto, o nada carga – Jakob

+0

@Jakob - Lo comprobaré. La muestra está en mi otra máquina, desafortunadamente. –

Cuestiones relacionadas