сериализируйте объект с подэлементами c#

хранилище var = GetStore (); использование (IsolatedStorageFileStream fileStream = хранилище. OpenFile (RootData, FileMode. Создайте)) {сериализатор DataContractSerializer = новый DataContractSerializer (typeof (Список)); сериализатор. WriteObject (fileStream, rootdatalist);}

Но это только сериализирует rootdatalist а не подэлементы. rootdatalist имеет свойство List узлов, как я сериализирую это, так, чтобы я сериализировал иерархию списка?

Так как это - сгенерированный dbml, возражает, что свойство Nodes Корня

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

Мой возврат Datacontext:

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

Узел entityset смотрит следующим образом в моем 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 Nodes
{
    get
    {
        if ((this.serializing && (this._Nodes.HasLoadedOrAssignedValues == false)))
        {
            return null;
        }
        return this._Nodes;
    }
    set
    {
        this._Nodes.Assign(value);
    }
}

Также я должен иметь [Include]тег выше моих свойств или ничто не будет загружено.Править:: Другим, желающим сериализировать dbml классы http://blogs.msdn.com/b/wriju/archive/2007/11/27/linq-to-sql-enabling-dbml-file-for-wcf.aspx

8
задан Jakob 5 July 2010 в 22:16
поделиться

3 ответа

Можете ли вы включить дополнительную информацию о типах контрактов? Я бы ожидал, например, что Root будет помечен как data-контракт, а член как data-member, например:

[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;}
}

Тогда это должно работать. Если нет, то было бы очень полезно увидеть ваши типы (или их урезанную версию, иллюстрирующую проблему).

9
ответ дан 5 December 2019 в 10:39
поделиться

DataContractSerializer должен знать о всех типах в вашем графе объектов.

Используйте перегрузку конструктора , которая позволяет вам указать их, а также корневой тип:

DataContractSerializer serializer = new DataContractSerializer(typeof(List<Root>), listOfOtherTypes);
7
ответ дан 5 December 2019 в 10:39
поделиться

OK; Я попытался воспроизвести это еще раз, используя таблицы Person / PersonPhone (в схеме Person ) из новой установки AdventureWorks2008R2.

У меня для контекста данных задана «однонаправленная» сериализация со стандартными привязками LINQ-to-SQL и т. Д. (Без настроек).

Для сравнения с вашим сценарием, Person может иметь PersonPhone s, и нас интересует список List . Я рассмотрел 3 сценария, в каждом из которых рассматривается полный набор данных:

  1. сериализация стандартного набора записей Person
  2. то же самое, что и 1, но с использованием LoadWith для получения телефонных записей
  3. то же самое, что и 1, но вручную повторять данные (примечание: это может вызвать N + 1 проблем)

Вот результаты; как вы можете видеть, 1 не работает так, как вы описываете, но 2 и 3 работают нормально, с той разницей, что 3 делает значительно работой TSQL.

Итак без дополнительных деталей (в идеале полностью воспроизводимый пример), очень трудно исследовать дальше ...

Результаты:

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

Испытательный стенд:

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));

    }
}

В качестве примечания, я мог бы настроить protobuf-net, чтобы убедить L2S предоставить ему данные (где DataContractSerializer решает игнорировать его), но это воспроизводит сценарий 3 с огромным Стоимость N + 1. Следовательно, я не планирую заниматься этим ...

0
ответ дан 5 December 2019 в 10:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: