2014-07-01 112 views
1

我想,這將是一個微不足道的問題,並會立即找到答案,但不知何故,互聯網證明了我的假設是錯誤的。映射和序列化雙向關聯

我有一個模型包含幾個實體之間有所有可能的關聯(1對1,1對許多,多對多,聚合,組成等)。爲了簡單起見,我們來看一下這個例子。我們有一個Person類和一個Car類。這個人可以擁有多輛汽車,但一輛汽車可以只屬於一個人(因此是一對多關係)。現在,在Person中創建一個List/ArrayList以保持他/她汽車的軌道將非常簡單。不過,我也想跟蹤車主的蹤跡。因此,這些類是這樣的:

[Serializable] 
public class Person 
{ 
    [XmlElement] 
    public List<Car> Cars { get; set; } 

    [XmlAttribute] 
    public string Name { get; set; } 

    public Person() 
    { 
     Cars = new List<Car>(); 
    } 
} 

[Serializable] 
public class Car 
{ 
    [XmlElement] 
    public Person Owner { get; set; } 

    [XmlAttribute] 
    public string Type { get; set; } 

    public Car() 
    { 
    } 
} 

不過,我相信,這種結構會導致XML文件中的無限循環,看起來像這樣:

<Person name="John Doe"> 
    <Cars> 
    <Car type="Ford"> 
     <Owner> 
     <Person name="John Doe"> 
      <Cars> 
      <Car type="Ford"> 
       <Owner> 
       <Person name="John Doe"> 
     ... etc. 

我甚至嘗試過了,在序列化我得到了「您需要將XmlChoiceIdentifierAttribute添加到」所有者「成員。」例外。

所以,我有幾個問題: 1.有沒有辦法來防止循環序列化? 2.如果不是,我是否必須爲每個類編寫自己的序列化程序? 3.這個映射是否正常?或者還有其他更好的方法嗎?我曾考慮過一箇中心的'Mapper'類,它會根據ID返回所需的對象...但是再次,這可以通過SQL完成。我想避免SQL(因爲保持應用程序的輕量級)。

回答

3

XmlSerializer是一個樹序列化器,而不是一個圖形序列化器。最好的辦法是通過具有避免向後序列化過程中導航,例如:

[XmlIgnore] 
public Person Owner { get; set; } 

(「父」和「老闆」幾乎總是向後導航)

不幸的是,XmlSerializer不支持序列化後回調,否則將有可能添加類似:

[WhateverOnAfterDeserialized] 
public void OnAfterDeserialized(...) { 
    foreach(var car in cars) car.Owner = this; 
} 

其他一些串行支持序列化回調,但該令牌,這些其它系列alizers也可能支持全圖序列化。例如,DataContractSerializer可以同時支持回調和完整圖形,但是它對xml的控制更少。

另一種選擇是創建一個自定義集合類型,用於在添加/刪除時維護父屬性;例如:

public class Person 
{ 
    private readonly CarCollection cars; 
    public Person() { 
     cars = new CarCollection(this); 
    } 
    [XmlElement] 
    public CarCollection Cars { get { return cars; } } 

    ... 
} 

與(在CarCollection):

// add code... 
innerList.Add(value); 
value.Parent = parent; // this is the field stored in the constructor 

我個人認爲,這可能是矯枉過正。

另一種選擇是簡單地添加你反序列化後調用一個固定式的方法,這確實一切必要(和瀑布向下):

public void FixupAfterDeserializer() { 
    foreach(var car in cars) car.Parent = this; 
} 

請注意,您必須手動調用。

最後,請注意[Serializable]對於XmlSerializer不是必需的。