La creación de un modelo de dominio sin referencias circulares en el Marco de la Entidad

StackOverflow https://stackoverflow.com/questions/19840537

  •  29-07-2022
  •  | 
  •  

Pregunta

He encontrado una solución que funciona (el uso de DTOs y AutoMapper), que se reproduce a continuación, pero yo preferiría una respuesta que muestra el diferentes enfoques para el problema con ejemplos y este será marcado como respuesta si la recibió.

En mi modelo de entidad tengo una propiedad de navegación que va de un niño de la entidad a la entidad matriz.Mi proyecto de trabajo swimmingly.Entonces comencé a usar AutoFixture para pruebas de unidad, pruebas y error, AutoFixture diciendo que tenía una referencia circular.

Ahora, me doy cuenta de que la circular de referencia de propiedades de navegación como este están bien dentro de Entity Framework, pero me he encontrado con este post (El valor de uso de una propiedad de matriz a la hora de crear un complejo de niño en AutoFixture), donde la Marca Seemann, el creador de AutoFixture estados:

"Para que conste, yo no he escrito una API con una referencia circular por años, así que es muy posible para evitar que los Padres/Hijo de relaciones."

Así que, quiero entender CÓMO un modelo de dominio puede ser refactorizado para evitar que los niños/padres de relaciones.

A continuación están las clases de entidad en cuestión, el repositorio de método, y cómo puedo utilizar la propiedad causando la circular de referencia, en mi Opinión. La respuesta ideal sería explicar las diferentes opciones que podía elegir, con ejemplos, y la base de los pros y los contras de cada enfoque.

Nota:La propiedad causando la circular de referencia es el Usuario, en el UserTeam modelo.

Modelos:

public class UserProfile
{
    public UserProfile()
    {
        UserTeams = new HashSet<UserTeam>();
        Games = new HashSet<Game>();
    }

    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public string UserName { get; set; }       

    public virtual ICollection<UserTeam> UserTeams { get; set; }
    public virtual ICollection<Game> Games { get; set; }
}


public class Game
{
    public Game()
    {
        UserTeams = new HashSet<UserTeam>();
    }

    public int Id { get; set; }
    public int CreatorId { get; set; }

    public virtual ICollection<UserTeam> UserTeams { get; set; }
}


public class UserTeam
{
    public UserTeam()
    {
        UserTeam_Players = new HashSet<UserTeam_Player>();
    }

    public int Id { get; set; }
    public int UserId { get; set; }
    public int GameId { get; set; }

    public virtual UserProfile User { get; set; }
    public virtual ICollection<UserTeam_Player> UserTeam_Players { get; set; }
}

Repositorio Método

public IEnumerable<Game> GetAllGames()
    {
        using (DataContext)
        {             
            var _games = DataContext.Games
                 .Include(x => x.UserTeams)
                 .Include(x => x.UserTeams.Select(y => y.User))
                 .ToList();
            if (_games == null)
            {
                // log error
                return null;
            }
            return _games;
        }
    }

Ver

@model IEnumerable<Game>
@foreach (var item in Model){
    foreach (var userteam in item.UserTeams){
        <p>@userteam.User.UserName</p>
    }
}

Ahora, si puedo quitar el 'Usuario', propiedad de navegación, yo no sería capaz de hacer '@userteam.Usuario.Nombre de usuario'

Así que, ¿cómo refactorizar el modelo de dominio para eliminar la referencia circular, mientras que ser capaz de bucle a través de los Juegos, y hacer algo como UserTeam.Usuario.Nombre de usuario?

¿Fue útil?

Solución

Yo tenía un problema similar con AutoFixture y EntityFramework hace un tiempo.Mi solución fue añadir una extensión a AutoFixture, que le permite construir un SUT con un par de repeticiones.Que la extensión ha sido recientemente aprobado en AutoFixture.

Pero entiendo que su pregunta no era sobre cómo hacer AutoFixture construir estructuras de datos recursivas, que es de hecho posible, pero, ¿cómo crear modelos de dominio sin recursividad.

En primer lugar, usted tiene o árbol de las estructuras de grafo.Aquí nada pero la recursividad significaría direccionamiento indirecto a través de la suelta junto id de nodo.En lugar de definir una asociación, tendría que recorrer el árbol de consulta por consulta o caché de toda la cosa y se atraviesan por el nodo de clave de búsqueda, los cuales pueden ser poco práctico dependiendo del árbol de tamaño.Aquí es muy conveniente para hacer EF hacer el trabajo por usted.

La otra estructura es una estructura de navegación similar a la de su usuario / escenario de juego.Aquí es a menudo no se que inconveniente para podar el flujo de navegación a una sola dirección.Si usted omite una dirección, digamos que de juego para el equipo, usted todavía puede fácilmente consulta de todos los equipos para un determinado juego.Así:El usuario tiene una lista de juegos y una lista de equipos.El equipo tiene una lista de juegos.Los juegos no tienen navegación referencia a cualquiera.Para obtener todos los usuarios para un juego específico podría escribir algo como:

var users = (from user in DataContext.Users
            from game in user.Games
            where game.Name == 'Chess'
            select user).Distinct()

Otros consejos

He encontrado una solución que funciona (el uso de DTOs y AutoMapper), que se reproduce a continuación, pero yo preferiría una respuesta que muestra el diferentes enfoques para el problema con ejemplos, en particular si se trata de una solución deseable, o si debo seguir con las propiedades de navegación como eran, deshacerse de AutoFixture, y cuando se trata de serialización json para sólo utilizar otras formas de resolver (atributos, etc)...

Así que, en mi Opinión, Modelo, he añadido un par de clases:

public class GameDTO
{
    public int Id { get; set; }
    public int CreatorId { get; set; }

    public ICollection<UserTeamDTO> UserTeamsDTO { get; set; }
}

public class UserTeamDTO : UserTeam
{
    public UserProfile User { get; set; }
}

Y en mi controlador, yo uso AutoMapper para asignar el Juego / UserTeam objetos del repositorio a mi DTO objetos, y el retorno a la interfaz IList _gamesDto a la Vista.

var _games = _gameRepository.GetAllGames();

IList<GameDTO> _gamesDto = new List<GameDTO>();
IList<UserTeamDTO> _userteamsDto = new List<UserTeamDTO>();
GameDTO _gameDto = new GameDTO();
UserTeamDTO _userteamDto = new UserTeamDTO();
Mapper.CreateMap<Game, GameDTO>();
Mapper.CreateMap<UserTeam, UserTeamDTO>();

foreach (Game _game in _games)
{
    foreach (UserTeam _userteam in _game.UserTeams)
    {
        _userteamDto = Mapper.Map<UserTeamDTO>(_userteam);
        _userteamDto.User = _userRepository.GetUser(_userteam.UserId);
        _userteamsDto.Add(_userteamDto);
    }

    _gameDto = Mapper.Map<GameDTO>(_game);
    _gameDto.UserTeamsDTO = _userteamsDto;
    _gamesDto.Add(_gameDto);
}

He tenido un problema similar recientemente que también ha afectado a serializar objetos JSON.He decidido quitar las referencias circulares de mi modelo de datos.

Primero me quitan el redundantes propiedades de navegación que fueron la creación de las referencias circulares.Me aseguré de que mi árbol resultante de los datos que se hayan sentido.Esto me permitió dejar claro que los objetos propios de la cual las relaciones.

Esto también hizo que EF no puede automáticamente razón acerca de mis relaciones.Yo tenía que especificar el Uno-a-muchos y Muchos-a-Muchos de relaciones con la FluentAPI.He encontrado una solución aquí: https://stackoverflow.com/a/16719203/1887885

Espero que esto sea útil.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top