2010-06-20 24 views
8

var store = GetStore(); (DataStorageFileStream fileStream = store.OpenFile(RootData,FileMode.Create)) 使用 serializer.WriteObject(fileStream,rootdatalist); }使用子項目序列化對象c#

但是,這只是序列化rootdatalist,而不是子項目。 rootdatalist有一個節點列表屬性,我如何序列化,以便我得到列表層次序列化?

,因爲它是DBML生成的對象根的節點屬性是

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

節點的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<Node> Nodes 
{ 
    get 
    { 
     if ((this.serializing && (this._Nodes.HasLoadedOrAssignedValues == false))) 
     { 
      return null; 
     } 
     return this._Nodes; 
    } 
    set 
    { 
     this._Nodes.Assign(value); 
    } 
} 

此外,我必須有[Include]標籤在我的屬性上方或沒有g將被加載。 編輯:: 要別人想序列化的dbml類http://blogs.msdn.com/b/wriju/archive/2007/11/27/linq-to-sql-enabling-dbml-file-for-wcf.aspx

+0

是否有任何[DataMember]信息在'Nodes'上方?這裏的「Root」是什麼?它暴露了一個「表」的事實使我認爲它是一個'DataContext',但'DataContext'不是(AFAIK)旨在成爲可序列化模型的一部分 - 它比域對象更像是管理器。 (從單向dbml生成類型的常規關係是'EntitySet ',而不是'表') – 2010-06-20 19:54:47

+0

它確實是datacontext的一部分,但我認爲當我添加單向序列化時,該對象是可序列化的我的帖子的底部鏈接。不幸的是,這似乎不太合適。我不太清楚我在做什麼錯誤 – Jakob 2010-06-20 20:26:19

+0

@Jakob - 完全; * data-context *不是可串行化的。它只是你的*域實體*成爲可序列化的。然而;你在這裏的目標是什麼?我可能有更多的技巧在我的袖子裏......(我虛心地說,我*痛苦地*熟悉.NET序列化的多種僞裝) – 2010-06-20 20:29:54

回答

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

這應該再工作。如果沒有,它會真正幫助您查看您的類型(或者它們的縮減版本,它可以說明問題)。

7

DataContractSerializer需要了解類型的所有在你的對象圖。

使用constructor overload,讓您指定這些以及根型:

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

如果列表實際上是EntityRef 在Root類中,這也可以工作嗎? – Jakob 2010-06-20 19:38:59

+0

@Jakob - 只要你告訴序列化程序關於類型的信息就可以了。請參閱Marc的回答,因爲您確實需要正確指定DataContract和DataMember。 – Oded 2010-06-20 19:42:06

+0

,因爲這是生成的,合同應該是正確的。在*大多數情況下,它不需要向ctor提供額外的數據。特別是,繼承可以通過'[KnownType]'等來處理。 – 2010-07-07 10:17:06

0

OK;我再次嘗試使用新的AdventureWorks2008R2安裝中的Person/PersonPhone表(在Person模式中)進行再現。

我有數據上下文設置爲「單向」序列化,與標準的LINQ到SQL綁定等(沒有自定義)。

要比較你的場景中,Person可以有PersonPhone秒,我們感興趣的是一個List<Person>。我已經看了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決定忽略它),但是這再現了劇烈的N + 1成本情況3。因此,我不打算追求...

+0

@Marc - 你想和ms teamviewer共享一個視圖,或者類似的東西嗎? – Jakob 2010-07-11 15:44:13

+0

@Marc - 元數據中是否有任何[include]標籤?我必須在我的項目中有這些,或者沒有加載 – Jakob 2010-07-11 16:09:39

+0

@Jakob - 我會檢查。不幸的是,樣品在我的另一臺機器上。 – 2010-07-11 17:45:40