VansFannel
VansFannel

Reputation: 45931

Pseudo recursive calls = stackoverflow

I'm developing an ASP.NET Web Api 2 service with .NET Framework 4.5.1 and C#.

I'm following this book to do it: ASP.NET MVC 4 and the Web API Building a REST Service from Start to Finish

I have these two classes.

User:

public class User
{
    public int UserId { get; set; }
    public string UserName { get; set; }

    public virtual ICollection<Group> Groups { get; set; }
}

Group:

public class Group
{
    public int GroupId { get; set; }
    public string GroupName { get; set; }

    public ICollection<User> Members { get; set; }
}

An User could have Groups, and a Group has Users as Members.

These two classes are my Data.Models and I use a Mapper class to 'translate' them as Api.Models with these two methods:

public Models.User CreateUser(Data.Models.User modelUser)
{
    if (modelUser == null)
        return null;

    Models.User user = new Models.User()
    {
        UserId = modelUser.UserId,
        UserName = modelUser.UserName
    };

    if (modelUser.Groups != null)
        user.Groups = modelUser.Groups
            .Select(CreateGroup)
            .ToList();
}

public Models.Group CreateGroup(Data.Models.Group modelGroup)
{
    if (modelGroup == null)
        return null;

    Models.Group group = new Models.Group
    {
        GroupId = modelGroup.GroupId,
        GroupName = modelGroup.GroupName
    };

    if (modelGroup.Members != null)
        group.Members = modelGroup.Members
            .Select(CreateUser)
            .ToList();

    return group;
}

As you can see in Mapper class, CreateUser method calls CreateGroup method, and CreateGroup method calls CreateUser.

In my case user1 is member of group1 and group1 has user1 as a member. So, I get this:

Any idea about how to avoid this infinite recursive calls?

A solution could be to remove navigation properties like Groups on User, or Members in Group class from CreateUser and CreateGroup methods.

Upvotes: 0

Views: 148

Answers (1)

Wiktor Zychla
Wiktor Zychla

Reputation: 48279

There are at least two possible solutions (I can think of two but there can be more).

  1. (simple graph) split both your mapper methods into two - first one to initialize simple properties (name, id) and the second one to initialize navigation properties. Then, in a place in your code where you call the mapper, write a little bit longer script that makes use of these new methods that initialize navigation properties from user to groups but do not call the other method (from groups to users) so that you will have a graph of users poiting to groups.

  2. (full graph) add a tail parameter to each of your methods that represents a list of objects that have already been visited. Then, upon recursive call, check if the element is already in the list and only if it is not - add it and call recursively. This way, recursive calls will explore whole dependency graph between users and groups and will make sure no user and no group is processed more than once.

Upvotes: 2

Related Questions