c#: no se puede asignar la propiedad de navegación interna usando automatapper. Núcleo EF

CorePress2024-01-24  10

Tengo entidades de este tipo para ese tema en particular: Álbum, Foto. Cada álbum contiene una colección de fotos.

Y clases Dto: AlbumWithPhotosDto, que contiene una colección de PhotoDto.

En mi perfil de automatapper describí las reglas de mapeo para todas las entidades:

CreateMap<Photo, PhotoDto>()
                .ForMember(dest => dest.AverageRate, opt => opt.MapFrom(src => src.Ratings.Average(r => r.Rate)))
                .ForMember(dest => dest.RatesCount, opt => opt.MapFrom(src => src.Ratings.Count))
                .ReverseMap();

 CreateMap<Album, AlbumWithPhotosDto>()
                .ForMember(dest => dest.PhotosNum, opt => opt.MapFrom(src => src.Photos.Count))
                .ReverseMap();

En primer lugar utilicé LazyLoadingProxies y cuando intenté asignar un álbum a un AlbumWithPhotosDto.

Recibí una excepción:

Tipos de asignación de errores.

Tipos de mapeo: Álbum -> ÁlbumConFotosDto DAL.Entidades.Álbum -> BLL.DataTransferObjects.AlbumWithPhotosDto

Configuración de tipo Mapa: Álbum -> AlbumWithPhotosDto DAL.Entidades.Album -> BLL.DataTransferObjects.AlbumWithPhotosDto

Miembro de destino: Fotos

Luego cambié la carga diferida por carga explícita comoes:

_context.Albums
            .Include(a => a.Photos)
            .Include(a => a.Author)

Pero nuevamente obtuve la misma excepción. ¿Cómo puedo solucionar esto?

Aquí las definiciones adicionales de clases:

 public class Album : IEntity<int>
    {
        public int Id { get; set; }
        /// <summary>
        /// Album name.
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// Album short description.
        /// </summary>
        public string Description { get; set; }
        /// <summary>
        /// Whether the other users can view and rate the album photos or not.
        /// </summary>
        public bool IsPrivate { get; set; }
        /// <summary>
        /// Foreign key, creator's id.
        /// </summary>
        public string AuthorId { get; set; }
        /// <summary>
        /// User who created the album but not obviously author of all photos.
        /// </summary>
        public virtual User Author { get; set; }
        /// <summary>
        /// Photos in album.
        /// </summary>
        public virtual ICollection<Photo> Photos { get; set; } = new HashSet<Photo>();
    }
public class Photo : IEntity<int>
    {
        public int Id { get; set; }
        /// <summary>
        /// Optional photo short description.
        /// </summary>
        public string Description { get; set; }
        /// <summary>
        /// Path to the photo file on the hard drive.
        /// </summary>
        public string FileName { get; set; }
        /// <summary>
        /// Date and time of uploading.
        /// </summary>
        public DateTime UploadDate { get; set; }
        /// <summary>
        /// Photo ratings by users.
        /// </summary>
        public virtual ICollection<Rating> Ratings { get; set; } = new HashSet<Rating>();
        /// <summary>
        /// Foreigh key, author's id.
        /// </summary> 
        public string AuthorId { get; set; }
        public virtual User Author { get; set; }
        public int AlbumId { get; set; }
        public virtual Album Album { get; set; }
    }
public class AlbumWithPhotosDto : IDtoMetadata
    {
        public int Id { get; set; }
        public string Description { get; set; }
        public string AuthorId { get; set; }
        public int PhotosNum { get; set; }
        public ICollection<PhotoDto> Photos { get; set; }
    }
public class PhotoDto : IDtoMetadata
    {
        public int Id { get; set; }
        public string Base64 { get; set; }
        public string Description { get; set; }
        public double AverageRate { get; set; }
        public int RatesCount { get; set; }
        public DateTime UploadDate { get; set; }
        public string AuthorId { get; set; }
        public ICollection<RatingDto> Ratings { get; set; }
    }

El mapeo de Clasificación también está presente, lo omití por brevedad

- Alexandr Barylo

27/03/2021 a las 20:10

Tal vez se eliminó el contexto. ¿Intentaste agregar un .ToArray()?al final de su consulta, antes del mapeo?

- Grappachu

27/03/2021 a las 20:15

Sí, forcé la ejecución de la consulta y los objetos del Álbum se consultaron correctamente, el contexto funciona bien

- Alexandr Barylo

27/03/2021 a las 20:24



------------------------------------

No incluiste las calificaciones en tu consulta. Por lo tanto, AutoMapper básicamente intenta llamar a .Average() en una colección vacía y, por lo tanto, falla.

Modifique su consulta como -

var albums = _context.Albums
            .Include(a => a.Photos).ThenInclude(p => p.Ratings)
            .Include(a => a.Author)
            .ToList();

2

Lo hice, nada cambió, comenté la colección de calificaciones en la clase dto, todo sigue igual.

- Alexandr Barylo

28/03/2021 a las 9:25

@AlexandrBarylo Entonces edite la publicación y comparta el código de mapeo completo, todos los modelos y también cómo está.Estamos llamando al método .Map().

-atiyar

28 de marzo de 2021 a las 9:33



------------------------------------

Como se indica en el mensaje de excepción, el problema está en la propiedad 'Fotos' en 'AlbumWithPhotosDto'. Cambie el tipo a 'Lista' e inténtelo de esa manera.



------------------------------------

Después de invertir paso a paso, me di cuenta de que el problema aún estaba en esa línea en la configuración del mapeo:

CreateMap<Photo, PhotoDto>()
                .ForMember(dest => dest.AverageRate, opt => opt.MapFrom(src => src.Ratings.Average(r => r.Rate)))

La solución fue cuidar un valor predeterminado encaso de 0 valoraciones.

CreateMap<Photo, PhotoDto>()
                .ForMember(dest => dest.AverageRate, opt => opt.MapFrom(src => src.Ratings.Select(r => r.Rate).DefaultIfEmpty(0).Average()))

Y ahora incluso los LazyLoadingProxies se asignan con éxito, lo que antes consideraba incompatible con el asignador automático.

randomThread
rendimiento - ¿Conversión de enteros saturada y rápida?javascript - Cómo obtener un botón cargar más para una lista li vue jsreactjs - Error de implementación de Vercel: el comando "npm run build" salió con 1python - Cómo implementar pytest.approx() para clases de datosflutter - ¿Es posible insertar AspectRatio en la columna?Desafío de codificación de JavaScript: cuadrícula de estrellasjavascript - ¿Cómo llamar a un php con parámetro de un