4

我查詢與父/子結果集使用實體框架的數據,我想將這些數據導出到XML文檔。序列化實體框架對象與兒童到XML文件

var agreement = storeops.Agreements.SingleOrDefault(a => a.AgreementNumber == AgreementTextBox.Text); 
XmlSerializer serializer = new XmlSerializer(agreement.GetType()); 
XmlWriter writer = XmlWriter.Create("Agreement.xml"); 
serializer.Serialize(writer, agreement); 

這個效果很好,除了它只在沒有在XML中包含相關子記錄的情況下序列化父文件。我怎樣才能讓孩子們序列化呢?

我也嘗試使用POCO生成的代碼和子集合嘗試被序列化,除了它們是不能被序列化的ICollections。

無法序列化System.Collections.Generic.ICollection`1 [[DataSnapshots.AgreementItem,DataSnapshots,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null]]類型的成員DataSnapshots.Agreement.AgreementItems,因爲它是接口。

回答

9

在使用實體框架實體時,XML序列化的行爲與二進制序列化和數據協定序列化行爲不同。後者將序列已裝載到目標圖中的任何相關的對象,但XML序列化沒有,所以你需要使用一個DataContractSerializer

var agreement = storeops.Agreements.SingleOrDefault(a => a.AgreementNumber == AgreementTextBox.Text); 
// make sure any relations are loaded 

using (XmlWriter writer = XmlWriter.Create("Agreement.xml")) 
{ 
    DataContractSerializer serializer = new DataContractSerializer(agreement.GetType()); 
    serializer.WriteObject(writer, agreement); 
} 

此外,實體框架採用延遲加載默認爲1:許多關係,並且如果被引用的對象在序列化的時候還沒有被加載,那麼你得到的只是引用它們的鍵。您必須通過在查詢中調用agreement.Children.Load()或使用.Include("Children")(其中"Children"是相關實體集合的名稱)來明確加載相關實體。

+0

我實際上得到的孩子,因爲我的數量大於0,但由於某些原因,他們沒有在XmlSerializer序列化。我猜這是因爲子對象不是一個真正的集合類,而是一個EntityCollection,它不能從任何Collection類繼承。 – 2011-06-05 02:19:04

+1

'EntityCollection'被定義爲'public sealed class EntityCollection :RelatedEnd,ICollection ,IEnumerable ,IEnumerable,IListSource',所以它肯定是*集合。 – 2011-06-05 04:34:15

+0

好的,我明白爲什麼子集合沒有被序列化到XML文檔中?除了孩子以外,所有其他的屬性都在那兒加載。我之所以說EntityCollection不像其他的collecions行爲是因爲我不能使用[]引用孩子。我想因爲這個,孩子們沒有被序列化。 – 2011-06-05 15:51:04

0

我終於想出了一個解決方案,這一點,但它確實需要編輯生成的類:(

創建POCO生成的實體類,設置延遲加載爲true這將讓家長和一個選擇的所有兒童(不無需使用包含或負載)。

在父類自ICollection修改孩子訪問類型FixupCollection。

公共虛擬FixupCollection AgreementItemLogs

然後在XmlSerializer中,您必須指定代理類中的父類型和子類型。

var agreement = storeops.Agreements.Include("AgreementItems").SingleOrDefault(a => a.AgreementNumber == AgreementTextBox.Text);            
       var typeList = new List<Type>(); 

       if(agreement.AgreementItems.Count > 0) 
        typeList.Add(agreement.AgreementItems.FirstOrDefault().GetType()); 
       if (agreement.AgreementItemLogs.Count > 0) 
        typeList.Add(agreement.AgreementItemLogs.FirstOrDefault().GetType()); 
       if (agreement.AgreementPricings.Count > 0) 
        typeList.Add(agreement.AgreementPricings.FirstOrDefault().GetType()); 
       if (agreement.AgreementSnapshots.Count > 0) 
        typeList.Add(agreement.AgreementSnapshots.FirstOrDefault().GetType()); 
       if (agreement.AgreementTransactions.Count > 0) 
        typeList.Add(agreement.AgreementTransactions.FirstOrDefault().GetType()); 
       if (agreement.AgreementTransactionLogs.Count > 0) 
        typeList.Add(agreement.AgreementTransactionLogs.FirstOrDefault().GetType()); 

       XmlSerializer serializer = new XmlSerializer(agreement.GetType(), typeList.ToArray()); 
       XmlWriter writer = XmlWriter.Create("Agreement.xml"); 
       serializer.Serialize(writer, agreement); 
+0

我更新了我的答案。一個'XmlSerializer'不會按你想要的方式工作,但是你可以很容易地使用'DataContractSerializer',因爲EF爲你生成DataContract。 – 2011-06-06 14:25:45