Bad Dub
Bad Dub

Reputation: 1593

LINQ Select Statement to Map Entity Using Recursion

I have a Category Entity that has a collection of child Categories and a nullable reference to a Parent Category.

public class Category
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int? ParentId { get; set; }

    public Category Parent { get; set; }
    public ICollection<Category> Children { get; set; } 
}

I have the scenario where I need to "copy" an existing entity (Zone) which has references to Categories. Within the select statement I need to map the existing categories and their children to a new Category record so that when I save the new categories will hold a reference to the new copied Zone.

The problem I'm having is a recursion method that will loop through the current LINQ select (x) Category and create new Category records for each of its children s children etc.

Here is the relevant part of the current "copy" select statement I have. Do I call Where on Categories that are top level i.e don't have a ParentId and then use a recursive method for the children?

Categories = zone.Categories.Where(y => !y.ParentId.HasValue).Select(x => new Category
{
     Children = WHAT DO I PUT IN HERE
     Name = x.Name,
}).ToList()

Upvotes: 1

Views: 200

Answers (2)

ChizT
ChizT

Reputation: 727

Use a select recursive method like so:

public static class EnumerableExtensions
{
    public static IEnumerable<T> SelectRecursive<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> selector)
    {
        foreach (var parent in source)
        {
            yield return parent;

            var children = selector(parent);
            foreach (var child in SelectRecursive(children, selector))
                yield return child;
        }
    }
}

Then do an implementation:

var lookup = _dbContext.Categories.ToLookup(x => x.ParentId);
var parents = lookup[null].SelectRecursive(x => lookup[x.Id]).Where(c => c.ParentId == null).ToList();

Upvotes: 0

Seva
Seva

Reputation: 1739

Are you perhaps looking for a copy constructor like this?

public class Category 
{
    // Copy constructor, recursively called for each child.
    public Category(Category other)
    {
        Id = other.Id;
        Name = other.Name;
        ParentId = other.ParentId;
        Parent = other.Parent;
        // Use this copy constructor for each child too:
        Children = other.Children.Select(c => new Category(c)).ToList();
    }
    // We probably want the default constructor too.
    public Category() { }

    // Your Props...
}

Usage:

var deepCopied = zone.Categories.Select(c => new Category(c));

Upvotes: 2

Related Questions