хранилище 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
Можете ли вы включить дополнительную информацию о типах контрактов? Я бы ожидал, например, что 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;}
}
Тогда это должно работать. Если нет, то было бы очень полезно увидеть ваши типы (или их урезанную версию, иллюстрирующую проблему).
DataContractSerializer
должен знать о всех типах в вашем графе объектов.
Используйте перегрузку конструктора , которая позволяет вам указать их, а также корневой тип:
DataContractSerializer serializer = new DataContractSerializer(typeof(List<Root>), listOfOtherTypes);
OK; Я попытался воспроизвести это еще раз, используя таблицы Person
/ PersonPhone
(в схеме Person
) из новой установки AdventureWorks2008R2.
У меня для контекста данных задана «однонаправленная» сериализация со стандартными привязками LINQ-to-SQL и т. Д. (Без настроек).
Для сравнения с вашим сценарием, Person
может иметь PersonPhone
s, и нас интересует список List
. Я рассмотрел 3 сценария, в каждом из которых рассматривается полный набор данных:
Person
LoadWith
для получения телефонных записей Вот результаты; как вы можете видеть, 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. Следовательно, я не планирую заниматься этим ...