Telerik OpenAccess Classic

Telerik OpenAccess ORM Send comments on this topic.
Using a XMLSerializer with Generics and Persistent Classes
Programmer's Guide > OpenAccess ORM Classic (Old API) > Programming With OpenAccess > The .NET Data Model > Using a XMLSerializer with Generics 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.

Problem:

The XMLSerializer has a problem to serialize generic IList<> instances (see http://pluralsight.com/blogs/craig/archive/2005/10/21/15770.aspx).

Solution:

Firstly, you can use ArrayList as in the past – it works and you can serialize these objects. However, if you want to use Generics you can use the pattern described below to make your persistent classes ready for the XMLSerializer.

The XMLSerializer accesses via the reflection API, all the public fields and public properties to retrieve the data; for creating a new object it needs a public constructor, and here again it accesses all the public fields and properties, via reflection.

On the other hand, Telerik OpenAccess ORM wraps all accesses to fields with generated methods to perform lazy loading and change tracking. What this means, is that the read or write access, from the XMLSerializer to public fields (unlike the access to public properties) is not noticed by the Telerik OpenAccess ORM tool, since the generated methods are not used, but bypassed by reflection. And this poses a problem, when a field is not initialized (refer to Transparent Persistence for more information about lazy loading and FetchGroups for more information about fetch groups). When an object, is created from the XMLSerializer it might be also a problem – since the Telerik OpenAccess ORM Library cannot see that the field has been changed, and it is possible that it is assumed that a reference is not set – even if it is. To avoid such problems, the class must be implemented very carefully. All fields must be non-public (so they are not touched by the XMLSerializer), and the XMLSerializer must get/set all its information via public properties.

As described above the IList<xxx> Interface from OpenAccess ORM cannot be directly converted to a List<xxx>, so the objects from the persistent IList<xxx> field must be copied to a transient List<xxx>.

When is the best point to do it?

It can be done within IInstanceCallbacks or partly inside the public property. In our example, we use the IInstanceCallbacks for all the needed conversions:

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

/**
* Remarks about retrieving objects
* The actual XMLSerializer from Microsoft accesses all
* public fields and public properties to get the needed values.
* Because of lazy loading from OpenAccess ORM an access to a field can fail
* (maybe the value isn't in the field at the time of access).
* So you must declare all fields private and access to them via
* public properties. In this case the internal loading mechanism
* of OpenAccess ORM ensures that the value of the field is retrieved
* from the database
*/


namespace ConsoleApplication1 {
 
class Program {
   
static void Main(string[] args) {
     
// --- create a test object
     
Company t = new Company();
     t.MyList.Add(
new Employee("John"));
     t.MyList.Add(
new Employee("Peter"));
     
// --- make a try when it is not persistent
     
DoSerialize(t);
     
// --- with objects
     
// --- create an ObjectScope and open a Transaction
     
IObjectScope scope =
          ObjectScopeProvider1.GetNewObjectScope();
     scope.Transaction.Begin();
     
// --- Add the test object
     
scope.Add(t);
     
// --- 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(t);
     
// --- clean up
     
scope.Transaction.Commit();
     scope.Dispose();
     Console.WriteLine(
"Finished!");
     Console.ReadLine();
 }

private static void DoSerialize(Company t) {
   
// --- create a Serializer and write the graph to a string
   
XmlSerializer ser = new XmlSerializer(typeof(Company));
   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 = (Company)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);
 }
}

[Persistent]
public class Employee{
   
private string lastname;
   
public Employee() { } //required

   
public Employee(string lastname) {
       
this.lastname = lastname;
   }

   
public string Lastname {
       get {
return lastname; }
       set { lastname = value; }               
   }
 }

 [Persistent]
 
public class Company : IInstanceCallbacks {
   
private int member = 4711;
   [Transient]
   
private List<Employee> list = new List<Employee>();

   
private IList<Employee> persistentList;
   
public int Member {
       get {
return member; }
       set { member = value; }
   }
   
//see blog on
   
//http://pluralsight.com/blogs/craig/archive/2005/10/21/15770.aspx
   //IList won't XML serialize
   
public List<Employee> MyList {
       get {
return list;      }
   }

   #region IInstanceCallbacks Members
   
void IInstanceCallbacks.PostLoad() {
       list.Clear();
       
foreach (Employee p in persistentList) {
           list.Add(p);
       }
   }

   
void IInstanceCallbacks.PreRemove(IObjectScope objectScope) {
   }

   
void IInstanceCallbacks.PreStore() {
       persistentList = list;
   }
   #endregion
 }
}