使用子项c#序列化对象

时间:2010-06-20 18:35:20

标签: c# serialization

var store = GetStore();     使用(IsolatedStorageFileStream fileStream = store.OpenFile(RootData,FileMode.Create))     {         DataContractSerializer serializer = new DataContractSerializer(typeof(List));         serializer.WriteObject(fileStream,rootdatalist);     }

但这只是序列化了rootdatalist,而不是子项目。 rootdatalist有一个节点List属性,我该如何序列化它,以便我得到列表层次结构序列化?

由于它是dbml生成的对象,因此Root的Nodes属性为

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

我的Datacontext返回是:

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

节点实体集在我的dbml designer

中看起来如下
[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);
    }
}

此外,我必须在我的属性上方添加[Include]标记,否则不会加载任何内容。 编辑:: 对于想要序列化dbml类http://blogs.msdn.com/b/wriju/archive/2007/11/27/linq-to-sql-enabling-dbml-file-for-wcf.aspx

的其他人

3 个答案:

答案 0 :(得分:9)

您能否包含有关合约类型的更多信息?例如,我希望期望Root标记为数据合同,并将该成员作为数据成员,例如:

[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;}
}
那应该有用。如果没有,那么查看你的类型(或者它们的简化版本,这说明了问题)真的很有帮助。

答案 1 :(得分:7)

DataContractSerializer需要了解对象图中所有类型的内容。

使用constructor overload,您可以指定这些以及根类型:

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

答案 2 :(得分:0)

行;我再次使用Person / PersonPhone表(在Person模式中)从新的AdventureWorks2008R2安装中重现了这一点。

我将数据上下文设置为“单向”序列化,使用标准的LINQ-to-SQL绑定等(无需自定义)。

要与您的方案进行比较,Person可以有PersonPhone个,我们对List<Person>感兴趣。我查看了3个场景,每个场景都在查看完整的数据集:

  1. 序列化一组香草Person条记录
  2. 与1相同,但使用LoadWith获取电话记录
  3. 与1相同,但手动迭代数据(注意:这可能会导致N + 1问题)
  4. 结果如下;正如你所看到的,1以你描述的方式失败,但2&amp; 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成本。因此,我不打算继续追求......