1

I have a tree construct in my application which contains hierarchical data of users.

public class User {
     //a lot of properties here like Id, Name, Last Name, etc.
     public IEnumerable<User> Employees {get;set;}
}

Now I need to replace certain record in this tree with new item.

var changedUsers = GetChangedUsers();
// Replace all changed user fields in original hierarchy 
// (only FirstName, LastName, etc. without touching Employees field)

Is there an elegant way to achieve this?

EDIT:

I have tried to loop with recursion, but stuck with updating record.

private void ReplaceUserInHierarchy(User modifiedUser, List<User> users)
        {
            foreach (var user in users)
            {
                if (user.Id == modifiedUser.Id)
                {
                    //we should update here somehow
                    return;
                }

                ReplaceUserInHierarchy(modifiedUser, user.Employees);
            }
        }
11
  • 2
    What degree of elegance is required? Is flattening hierarchy and editing each matched user elegant enough? Commented Jul 10, 2017 at 12:36
  • Was that a sarcasm? Commented Jul 10, 2017 at 12:39
  • @Gab flatten hierarchy and join to changedUsers Commented Jul 10, 2017 at 12:40
  • @Gab exactly. Your question missing the main part - code which shows your attempt to solve this task and description of problem (error or incorrect results) which you can't solve Commented Jul 10, 2017 at 12:42
  • @tchelidze - How can we do that? Commented Jul 10, 2017 at 12:43

1 Answer 1

2

Simply update user wich matched given id:

private void ReplaceUserInHierarchy(User modifiedUser, List<User> users)
{
    foreach (var user in users)
    {
        if (user.Id == modifiedUser.Id)
        {
            // update properties of user here
            user.FirstName = modifiedUser.FirstName;
            // etc
            return; // if user can be duplicated in hierarchy, then use continue here
        }

        // assume user cannot be in own employees hierarchy
        ReplaceUserInHierarchy(modifiedUser, user.Employees);
    }
}

Improving elegance - you can use extension method which flattens hierarchy. Then search for the user you should update will look like:

var user = users.Flatten(u => u.Employees).FirstOrDefault(u => u.Id == modifiedUser.Id);
if (user != null) // you can throw if user not found
    user.FirstName = modifiedUser.FirstName; // etc        

Flattening can be done as

public static IEnumerable<T> Flatten<T>(
   this IEnumerable<T> source,
   Func<T, IEnumerable<T>> selector)
{
   // null-check arguments
   foreach(var item in source)
   {
       yield return item;
       foreach(var child in Flatten(selector(item), selector))
           yield return child;
   }   
}

Further improvements - you can save flattened hierarchy to the dictionary and use it to update several users:

var usersById = users.Flatten(u => u.Employees).ToDictionary(u => u.Id);
foreach(var modifiedUser in modifiedUsers)
{
    User user;
    if (!usersById.TryGetValue(modifiedUser.Id, out user);)
       continue; // or throw

    user.FirstName = modifiedUser.FirstName; // etc  
}

Further improvements - you can use some library like AutoMapper to do the mapping automatically.

Sign up to request clarification or add additional context in comments.

9 Comments

Is there a way I can say to replace all properties except Employees? (there are about 30 properties)
Note the last s in GetChangedUsers();, your code only caters for one.
@Gab - sounds like you need to look at AutoMapper or similar.
@HenkHolterman my code changes all references of user which have id of modifiedUser
Still I think I need to use "return" instead of "continue" - There can be only single user with specified Id in hierarchy.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.