Исключение Stackoverflow с объектом отношения «многие ко многим» в структуре сущностей - PullRequest
0 голосов
/ 12 апреля 2019

Я использую Entity Framework в .net core. Обратите внимание, что мои знания об Entity Framework несколько ограничены, поэтому возьмите мои предположения с нуля.

Команды и пользователи - это два объекта, с которыми у меня проблемы.

У них есть объединяющий стол, UserTeam, потому что Users может иметь много Teams, а Teams может иметь много Users.

Я выяснил, как сохранить их в базе данных sqlite с помощью entityframework, и все в порядке. Мне потребовалось некоторое время, чтобы понять, что я должен был использовать Include, чтобы получить свойство соединения, но теперь это работает в этой части.

В какой-то момент я должен выставить этот объект в API, поэтому у меня совпадают UserDTO & TeamDTO. Есть моя проблема. У UserDTO есть список TeamDTO с, а у TeamDTO есть список UserDTO, потому что так они должны выглядеть. Верно?

Но когда я сопоставляю их, я попадаю в StackOverflowException, что нормально, потому что я зацикливаюсь на списке команд, который содержит Users, и для каждой из этих Users я заканчиваю до воссоздания Teams и т. д.

Прямо сейчас, я просто добавил логическую проверку в цикле, поэтому, когда я вызываю .ToDTO(), я могу решить пропустить пользователей / команды с внутренних уровней, но это не похоже на правильное решение для меня. Это так?

Что вы, ребята, предлагаете?

Вот что я делаю именно:

public static TeamDTO ToDTO(this Team team, EatupContext context, bool doOnce = false)
{
    var dto = new TeamDTO
    {
        Id = team.Id,
        Name = team.Name,
    };

    var users = new List<UserDTO>();
    foreach (var userTeam in team.UsersTeams)
    {
        var user = context.Users.Find(userTeam.UserId);

        if (doOnce)
            user.TeamsUsers = new List<UserTeam>();

        users.Add(user.ToDTO(context, true));
    }

    dto.Users = users;

    return dto;
}
public static UserDTO ToDTO(this User user, EatupContext context, bool doOnce = false)
{
    var dto = new UserDTO
    {
        Id = user.Id,
        NickName = user.NickName,
        Email = user.Email,
        Image = user.Image,

    };

    var teams = new List<TeamDTO>();
    foreach (var userTeam in user.TeamsUsers)
    {
        var team = context.Teams.Find(userTeam.TeamId);
        if (doOnce)
            team.UsersTeams = new List<UserTeam>();
        teams.Add(team.ToDTO(context, true));
    }

    dto.Teams = teams;

    return dto;
}

Поскольку у меня сильное чувство, что моя проблема может возникнуть оттуда, я поделюсь этой информацией:

Когда я перебираю объекты сущности UserTeams (команды или пользователя), объект Team равен null, поэтому мне нужно извлечь Team из контекста, используя его идентификатор и тогда у меня есть все, что мне нужно. Это очень странно, потому что кажется, что все работает нормально, а база данных полна и здорова. Это просто объект UserTeam, в котором отсутствует свойство Team.

Но я предполагаю, что между извлечением нового Team из идентификатора и получением Team из UserTeam оба получат тот же результат, что и сейчас, когда я звоню ToDTO(): я все равно буду нужно пройти через своих пользователей и иметь это исключение переполнения.

Кажется, это очень распространенная проблема, с которой следовало бы бороться многим людям, но я не могу найти ответ, используя ключевые слова моего названия.

Какой у меня следующий шаг?

1 Ответ

0 голосов
/ 12 апреля 2019

Вы получаете переполнение стека из-за того, что циклически вызываете 2 метода.

В групповой версии метода ToDTO вы вызываете пользовательскую версию, которая, в свою очередь, вызывает командную версию и т. Д.

Если ваша модель не структурирована, как показано ниже, вы должны рассмотреть это. Нет необходимости на самом деле моделировать UserTeam, так как EFs mapping должна позаботиться об этом. Это с учетом того, что вы указали один конец отношения в качестве основного.

public class Team
{
    public Team()
    {
        Users = new List<User>();
    }
    //properties we don't care about

    public virtual ICollection<User> Users {get;set;}
}

public class User
{
    public User()
    {
        Teams = new List<User>();
    }

    //properties we don't care about

    public virtual ICollection<Team> Teams {get;set;}
}
...