无法使用自动映射器映射内部导航属性。 EF 核心
Posted
技术标签:
【中文标题】无法使用自动映射器映射内部导航属性。 EF 核心【英文标题】:Cannot map inner navigation property using automapper. EF Core 【发布时间】:2021-06-24 09:14:50 【问题描述】:我有针对该特定问题的此类实体:Album
、Photo
。每个Album
都包含一个Photo
s 的集合。
和 Dto 类:AlbumWithPhotosDto
,其中包含PhotoDto
的集合。
在我的自动映射器配置文件中,我描述了所有实体的映射规则:
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();
首先我使用LazyLoadingProxies
,当我尝试将Album
映射到AlbumWithPhotosDto
时。
我遇到了异常:
错误映射类型。
映射类型:相册 -> AlbumWithPhotosDto DAL.Entities.Album -> BLL.DataTransferObjects.AlbumWithPhotosDto
类型映射配置:相册 -> AlbumWithPhotosDto DAL.Entities.Album -> BLL.DataTransferObjects.AlbumWithPhotosDto
目标成员:照片
然后我在显式加载时更改了延迟加载,例如:
_context.Albums
.Include(a => a.Photos)
.Include(a => a.Author)
但我又遇到了同样的例外。我该如何解决这个问题?
这里是类的附加定义:
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;
【问题讨论】:
Rating 的映射也存在,为了简洁,我跳过了这个 可能上下文已被处理。在映射之前,您是否尝试在查询末尾添加 .ToArray()? 是的,我强制执行查询,成功查询了相册对象,上下文正常 【参考方案1】:您的查询中没有包含Ratings
。因此,AutoMapper 基本上是试图在一个空集合上调用.Average()
,因此失败了。
将您的查询修改为 -
var albums = _context.Albums
.Include(a => a.Photos).ThenInclude(p => p.Ratings)
.Include(a => a.Author)
.ToList();
【讨论】:
我做了,没什么变化,我把dto类里的ratings集合注释掉了,都是一样的。 @AlexandrBarylo 那么请编辑帖子并分享完整的映射代码、所有模型,以及您如何调用.Map()
方法。【参考方案2】:
正如异常消息中所述,问题在于“AlbumWithPhotosDto”中的“照片”属性。将类型更改为“列表”,然后尝试这种方式。
【讨论】:
【参考方案3】:经过一步一步的投资,我意识到问题出在映射配置中的那一行:
CreateMap<Photo, PhotoDto>()
.ForMember(dest => dest.AverageRate, opt => opt.MapFrom(src => src.Ratings.Average(r => r.Rate)))
解决方案是在评分为 0 时注意默认值。
CreateMap<Photo, PhotoDto>()
.ForMember(dest => dest.AverageRate, opt => opt.MapFrom(src => src.Ratings.Select(r => r.Rate).DefaultIfEmpty(0).Average()))
现在连我之前认为与自动映射器不兼容的 LazyLoadingProxies 都已成功映射。
【讨论】:
以上是关于无法使用自动映射器映射内部导航属性。 EF 核心的主要内容,如果未能解决你的问题,请参考以下文章
当我的类中有属性具有默认构造函数来提供值自动映射器时,如何映射?