views:

42

answers:

1

I'm trying to serialize an entity and all its related entities for storing as xml before physically deleting the entity (leaving an audit trail).

I'm using a DataContractSerializer which seems to be getting around the shallow serialization performed when using an XmlSerializer.

The only trouble is that only related entities that have been loaded get serialized.

I've tried to create a helper function that will take any entity and iterate though its properties looking for related entities to load, however its failing on EntityCollection properties because I can't cast them to EntityCollection<EntityObject>. I was trying to use EntityObject as I figured polymorphism would come to my aid, but the property won't cast complaining it's a different type.

Any ideas?

/// <summary>
/// Forces loading of all related entities.
/// </summary>
/// <param name="processed">Processed entities, used to prevent infinite looping.</param>
private static void LoadAllRelatedEntities(EntityObject entity, List<EntityKey> processed)
{
    // Check we haven't already processed this entity
    foreach (EntityKey key in processed)
    {
        if (entity.EntityKey == key)
            return; // Exit without doing anything more with this entity
    }

    processed.Add(entity.EntityKey);

    // Pull in all child entities
    foreach (PropertyInfo p in entity.GetType().GetProperties())
    {
        if (p.PropertyType == typeof(EntityReference) || p.PropertyType.BaseType == typeof(EntityReference))
        {
            if (p.GetValue(entity, null) != null)
            {
                EntityReference e = (EntityReference)p.GetValue(entity, null);
                if (!e.IsLoaded)
                    e.Load();

                // Load child entities
                IEnumerator eEnum = e.GetEnumerator();
                while (eEnum.MoveNext())
                {
                    LoadAllRelatedEntities((EntityObject)eEnum.Current, processed);
                }
            }
        }
        else if (p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(EntityCollection<>))
        {
            EntityCollection<EntityObject> e = (EntityCollection<EntityObject>)p.GetValue(entity, null);
            if (!e.IsLoaded)
                e.Load();

            // Load child entities
            IEnumerator eEnum = e.GetEnumerator();
            while (eEnum.MoveNext())
            {
                LoadAllRelatedEntities((EntityObject)eEnum.Current, processed);
            }
        }
    }
}
A: 

I found a solution that did what I want:

else if (p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(EntityCollection<>))
{
    IEnumerable pEnum = (IEnumerable)p.GetValue(entity, null);

    IRelatedEnd pEnd = (IRelatedEnd)p.GetValue(entity, null);
    pEnd.Load();

    // Load child entities
    IEnumerator eEnum = pEnum.GetEnumerator();
    while (eEnum.MoveNext())
    {
        LoadAllRelatedEntities((EntityObject)eEnum.Current, ref processed);
    }
}

I also needed to change the processed param to a ref so it worked as required:

LoadAllRelatedEntities(EntityObject entity, ref List<EntityKey> processed)

In my case I also had to add some filtering to which entities I would load as in my case a lot were self-referencing somewhere down the chain and so caused endless looping.

Gavin