views:

98

answers:

1

I have an entity that is actually tree object structure (defining only relevant properties within my entity):

public class TreeItem
{

    public int Id { get; set; }

    public TreeItem Parent { get; set; }

    public List<TreeItem> Children { get; set; }

    ...

}

Parent and Children properties are correctly defined as navigational properties. So when I call something like:

var items = (from ti in context.TreeItem()
            select ti).ToList<TreeItem>();

I actually get my items in a tree structure, because EF works its magic behind the curtain and populates my Parents and Children on these items.

What I would like to do now is to convert these objects into my ViewModel objects that are very much POCO. No functionality, just data.

I could convert these by having a recursive method that would create and populate new objects, but is there a simpler (in terms of LoC - lines of code) way to do this kind of conversion?

+1  A: 

In this related question several approaches are discussed:

  • The recursive one, will probably be the easiest to implement, however in terms of scaling for depth and number of items, it is limited as it tends to exponentially take longer and risks overflowing your stack
  • Another approach would be to use a stack which in terms of scaling has a much more linear growth

Be sure to check out Eric Lippert's comment at the bottom of the page.

Update, to give you an idea of what I mean:

public static class Extensions
{
    public static IList<R> TransformTree<T, R>(this IEnumerable<T> collection,
        Func<T, IEnumerable<T>> entitySelector,
        Func<R, IList<R>> pocoSelector,
        Func<T, R> transformer)
    {
        var transformedList = new List<R>();
        var stack = new Stack<IEnumerable<T>>();
        var parents = new Dictionary<IEnumerable<T>, R>();

        stack.Push(collection);

        while (stack.Count > 0)
        {
            IEnumerable<T> items = stack.Pop();

            R transformedParent;

            IList<R> parentChildren = parents.TryGetValue(items, out transformedParent)
                                          ? pocoSelector(transformedParent)
                                          : transformedList;

            foreach (var item in items)
            {
                R transformedItem = transformer(item);
                parentChildren.Add(transformedItem);

                IEnumerable<T> children = entitySelector(item);

                stack.Push(children);
                parents.Add(children, transformedItem);
            }
        }

        return transformedList;
    }
}

Call it like so:

treeItems.TransformTree<TreeItem, TreeItemPoco>(
  (item) => { return item.Children; },
  (pocoItem) => { return pocoItem.Children; },
  (item) => { return new TreeItemPoco(item); });
Yannick M.
Stack approach seems to be much faster than recursion, but it still needs a considerable amount of lines. I was looking for a simple trick in form of a series of extension method calls and/or lambdas... but I'll use stacks if nothing else comes along.
Robert Koritnik
But looking at it closely the stack approach flattens a tree structure to an IEnumerable<T>. I want to convert a tree structure to a different type tree structure, so this isn't really helping me.
Robert Koritnik
I am aware; keep in mind that you only want to walk the tree and do something with it. Be it flattening, or recreating a tree structure with POCOs. Both approaches should still work.
Yannick M.