Serialize Entity Framework object with children in an XML file

I am querying data with parent / child result sets using the Entity Framework and I want to export this data to an XML document.

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

This works well, except that it only serializes the parent without including related child records in XML. How can I make children serialize as well?

I also tried using the code generated by POCO, and the child collections tried to serialize, except that they are ICollections that cannot be serialized.

It is not possible to serialize the DataSnapshots.Agreement.AgreementItems element of type System.Collections.Generic.ICollection`1 [[DataSnapshots.AgreementItem, DataSnapshots, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null]], because it is an interface.

+4
source share
2 answers

XML serialization behaves differently than binary serialization and serialization of data contracts when working with Entity Framework objects. The latter will serialize any related objects that have been loaded into the object graph, but XML serialization does not work, so you will need to use 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); } 

In addition, the Entity Framework by default uses lazy loading for 1: Many relationships, and if the referenced objects are not loaded yet when you go to serialization, then all you get is the keys that apply to them. You must explicitly load the related objects either by calling agreement.Children.Load() or using .Include("Children") in your request (where "Children" is the name of the collection of related objects).

+9
source

I finally decided to solve this, but requires editing the generated classes :(

Create POCO entity classes, set Lazy Loading to true to get the parent and all children with the same select (without the need for Include or Load).

In the parent class, change the type of the child accessor from ICollection to FixupCollection.

public virtual agreement FixupCollectionItemLogs

Then in the XmlSerializer you must specify the parent type and child types from the proxy classes.

 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
source

All Articles