Telerik OpenAccess Classic

Telerik OpenAccess ORM Send comments on this topic.
How to: Use XmlSerializer with Generic Lists and Persistent Classes
Programmer's Guide > OpenAccess ORM Classic (Old API) > OpenAccess Tasks > Working with Objects > How to: Use XmlSerializer with Generic Lists and Persistent Classes

Glossary Item Box

This documentation article is a legacy resource describing the functionality of the deprecated OpenAccess Classic only. The contemporary documentation of Telerik OpenAccess ORM is available here.

The XmlSerializer class does not support IList<> directly. This article shows how to serialize persistent classes with IList<> members to XML.
Currently, OpenAccess supports collection interfaces from the System.Collections.Generic namespace only, specifically these are: ICollection<>, IList<> and IDictionary<> in addition to the list implementations TrackedList<> and TrackedBindingList<T>.
In order to serialize an IList collection you can use the TrackedList<T> implementation provided by OpenAccess. Instances of this class are XML serializable. This is the recommended way as it is the most convenient one.
The System.Collections.ArrayList class could be used instead of IList<T>. It supports serialization but you lose the safety of the generic type.
Alternatively, if you want to use Generics you can use the following pattern to make your persistent classes ready for the XmlSerializer. The idea behind this is creating a tiny wrapper around the IList<T> (which is not serializable to XML) that does nothing but serialization. All you need to do then is to make sure that a public property is available which allows to access this wrapper instance and to exclude the original (now wrapped) field from the XML serialization.

C# Copy Code
using System;  
using System.Collections.Generic;  
using System.Text;  
using System.Xml.Serialization;  
using System.IO;  
using Telerik.OpenAccess;  

namespace XMLSerialization  
{  
   
class Program  
   {  
       
static void Main(string[] args)  
       {  
           
// --- create a test object  
           
Person p = new Person("Jack");  
           p.Addresses.Add(
new Address("New York"));  
           p.Addresses.Add(
new StreetAddress("Dallas", "Main Street"));  
           
// --- make a try when it is not persistent  
           
DoSerialize(p);  
           
// --- with persistent classes  
           
// --- create an ObjectScope and open a Transaction  
           
IObjectScope scope = ObjectScopeProvider1.GetNewObjectScope();  
           scope.Transaction.Begin();  
           
// --- Add the test object  
           
scope.Add(p);  
           
// --- Store it in the database  
           
scope.Transaction.Commit();  
           
// --- Start a new transaction  
           
scope.Transaction.Begin();  
           
//// --- Retrieve the object from the database  
           
//// --- see remarks about hollow references  
           
//scope.Retrieve(t);  
           
// --- make a try with the objects  
           
DoSerialize(p);  
           
// --- clean up  
           
scope.Transaction.Commit();  
           scope.Dispose();  
           Console.WriteLine(
"Finished!");  
           Console.ReadLine();  
       }  

       
private static void DoSerialize(Person t)  
       {  
           
// --- create a Serializer and write the graph to a string  
           
XmlSerializer ser = new XmlSerializer(typeof(Person));  
           StringWriter writer =
new StringWriter();  
           ser.Serialize(writer, t);  
           
// --- show the graph on the screen  
           
Console.WriteLine(writer);  
           
// --- now backwards  
           
// --- but what we get is a new object which is not managed by  
           
// --- our ObjectScope  
           
t = (Person)ser.Deserialize(new StringReader(writer.ToString()));  
           
// --- write all out to make sure nothing is missing  
           
writer = new StringWriter();  
           ser.Serialize(writer, t);  
           Console.WriteLine(writer);  
       }  
   }  

   
public class XMLList<T> : IList<T>, IXmlSerializable  
   {  
       
private readonly IList<T> src;  

       
public XMLList(IList<T> wrapped)  
       {  
           
if (wrapped == null) throw new ArgumentNullException("wrapped");  
           src = wrapped;  
       }  

       
public XMLList() : this(new List<T>()) { }  

       
public void Update(IList<T> target)  
       {  
           
if (target == null) throw new ArgumentNullException("target");  
           
bool changed = target.Count != src.Count;  
           
if (!changed)  
           {  
               
for (int i = src.Count - 1; i >= 0; i--)  
               {  
                   T s = src[i];  
                   T t = target[i];  
                   
if (s == null && t == null)  
                   {  
                   }  
                   
else if (s == null || t == null)  
                   {  
                       changed = true;
break;  
                   }  
                   
else if (s.Equals(t))  
                   {  
                       changed = true;
break;  
                   }  
               }  
           }  
           
if (changed)  
           {  
               target.Clear();  
               
for (int i = 0; i < src.Count; i++)  
                   target.Add(src[i]);  
           }  
       }
       #region IXmlSerializable Members  

       System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()  
       {  
           
return null;  
       }  

       
void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)  
       {  
           
if (reader.IsEmptyElement || reader.Read() == false)  
               
return;  
           XmlSerializer inner =
new XmlSerializer(typeof(T));  
           
while (reader.NodeType != System.Xml.XmlNodeType.EndElement)  
           {  
               T e = (T)inner.Deserialize(reader);  
               src.Add(e);  
           }  
           reader.ReadEndElement();  
       }  

       
void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)  
       {  
           
if (src.Count == 0)  
               
return;  
           XmlSerializer inner =
new XmlSerializer(typeof(T));  
           
for (int i = 0; i < src.Count; i++)  
           {  
               inner.Serialize(writer, src[i]);  
           }  
       }
       #endregion  

       #region IList<T> Members  

       
int IList<T>.IndexOf(T item)  
       {  
           
return src.IndexOf(item);  
       }  

       
void IList<T>.Insert(int index, T item)  
       {  
           src.Insert(index, item);  
       }  

       
void IList<T>.RemoveAt(int index)  
       {  
           src.RemoveAt(index);  
       }  

       T IList<T>.
this[int index]  
       {  
           get {
return src[index]; }  
           set { src[index] = value; }  
       }
       #endregion  

       #region ICollection<T> Members  

       
void ICollection<T>.Add(T item)  
       {  
           src.Add(item);  
       }  

       
void ICollection<T>.Clear()  
       {  
           src.Clear();  
       }  

       
bool ICollection<T>.Contains(T item)  
       {  
           
return src.Contains(item);  
       }  

       
void ICollection<T>.CopyTo(T[] array, int arrayIndex)  
       {  
           src.CopyTo(array, arrayIndex);  
       }  

       
int ICollection<T>.Count  
       {  
           get {
return src.Count; }  
       }  

       
bool ICollection<T>.IsReadOnly  
       {  
           get {
return src.IsReadOnly; }  
       }  

       
bool ICollection<T>.Remove(T item)  
       {  
           
return src.Remove(item);  
       }
       #endregion  

       #region IEnumerable<T> Members  

       IEnumerator<T> IEnumerable<T>.GetEnumerator()  
       {  
           
return src.GetEnumerator();  
       }
       #endregion  

       #region IEnumerable Members  

       System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()  
       {  
           
return ((System.Collections.IEnumerable)src).GetEnumerator();  
       }
       #endregion  
   }  

   [Persistent]  
   
public class Person  
   {  
       
private IList<Address> addresses;  
       
private string name;  

       Person() { }  
       
public Person(string theName) { name = theName;   
                                       addresses =
new List<Address>(); }  

       [XmlIgnore]
// Will be handled by XMLWrapper4Addresses property.  
       
public IList<Address> Addresses  
       {  
           get {
return addresses; }  
           set { addresses = value; }  
       }  

       [XmlElement(
"Addresses")] // The other field is not XML serialized.  
       
public XMLList<Address> XMLWrapper4Addresses  
       {  
           get {
return new XMLList<Address>(Addresses); }  
           set
           {  
               
if (Addresses == null) Addresses = new List<Address>();  
               value.Update(Addresses);  
           }  
       }  

       
public string Name  
       {  
           get {
return name; }  
           set { name = value; }  
       }  
   }  

   [XmlInclude(
typeof(StreetAddress))]  
   [Persistent]  
   
public class Address  
   {  
       
private string city;  

       
internal Address() { }  
       
public Address(string theCity) { city = theCity; }  

       
public string City  
       {  
           get {
return city; }  
           set { city = value; }  
       }  
   }  

   [Persistent]  
   
public class StreetAddress : Address  
   {  
       
private string street;  

       StreetAddress() { }  
       
public StreetAddress(string theCity, string theStreet)   
              :
base(theCity) { street = theStreet; }  

       
public string Street  
       {  
           get {
return street; }  
           set { street = value; }  
       }  
   }  
}   
In this code the XMLList<T> class acts as a delegate providing just the bit of missing XML serialization functionality. A public property of that type was defined and acts as the proxy for the non-serializable IList<T> property, which was excluded from the serialization process. The example additionally shows how to deal with polymorphism. It is most suited for situations, where using interface typed fields and properties are of biggest importance.