【发布时间】:2017-05-22 23:58:16
【问题描述】:
初始化映射器
public static class MapperConfig
{
public const int MAX_MAPPING_DEPTH = 2;
private static MapperConfiguration _config;
private static IMapper _mapper;
public static IMapper Mapper => _mapper ?? (_mapper = GetConfig().CreateMapper());
public static MapperConfiguration GetConfig()
{
var assembly = Assembly.GetExecutingAssembly();
if (_config != null)
return _config;
_config = new MapperConfiguration(cfg =>
{
cfg.AddProfiles(assembly);
cfg.ForAllMaps(ConfigTypeMapping);
});
_config.AssertConfigurationIsValid();
return _config;
}
public static void ConfigTypeMapping(TypeMap map, IMappingExpression expression)
{
map.ShouldCheckForValid();
expression.PreserveReferences();
expression.MaxDepth(MAX_MAPPING_DEPTH);
//expression.ForAllMembers(m => m.UseDestinationValue());
}
}
主要实体
[ResourceKey("MEDIA_ITEM")]
public class MediaItem : SocialEntity
{
/// <summary>
/// User-defined media item <see cref="Title"/> or its original file name.
/// </summary>
public string Title { get; set; }
/// <summary>
/// The original <see cref="FileName"/>.
/// </summary>
public string FileName { get; set; }
/// <summary>
/// The <see cref="FileGuid"/> that refers to the CDN file entry.
/// </summary>
public Guid FileGuid { get; set; }
/// <summary>
/// The purpose / group (aka <see cref="Type"/>) for this <see cref="MediaItem"/>.
/// </summary>
public FileType Type { get; set; }
/// <summary>
/// Allows limiting retrieval of this <see cref="MediaItem"/> depending on a specific <see cref="PrivacyLevel"/>.
/// </summary>
public PrivacyLevel PrivacyLevel { get; set; }
/// <summary>
/// The <see cref="Source"/> for the Content / File of this <see cref="MediaItem"/>.
/// </summary>
public virtual Url Source { get; set; }
public Guid? SourceGuid { get; set; }
/// <summary>
/// The <see cref="Profile"/> entity that this media file is bound to.
/// </summary>
public virtual Profile Profile { get; set; }
public Guid? ProfileGuid { get; set; }
/// <summary>
/// The <see cref="Article"/> entity that this media file is bound to.
/// </summary>
public virtual Article Article { get; set; }
public Guid? ArticleGuid { get; set; }
/// <summary>
/// The <see cref="Communication.Comment"/> entity that this media file is bound to.
/// </summary>
public virtual Comment Comment { get; set; }
public Guid? CommentGuid { get; set; }
/// <summary>
/// The <see cref="Theme"/> entity that this media file is bound to.
/// </summary>
public virtual Theme Theme { get; set; }
public Guid? ThemeGuid { get; set; }
}
如您所见,该实体继承自 SocialEntity,该 SocialEntity 包含一堆默认集合。然后,SocialEntity 继承基类 Entity 以及 Id、用户、创建日期等。
基类映射
CreateMap<SocialEntity, SocialDomainModel>()
.IncludeBase<Entity, DomainModel>()
.ReverseMap()
.IncludeBase<DomainModel, Entity>();
CreateMap<Entity, DomainModel>()
.IncludeBase<global::Data.Pattern.Entity.Entity, DomainModel>()
.ReverseMap()
.IncludeBase<DomainModel, global::Data.Pattern.Entity.Entity>();
CreateMap<global::Data.Pattern.Entity.Entity, DomainModel>()
.ForMember(dm => dm.Creator, mo => mo.Ignore())
.ForMember(dm => dm.CreatorGuid, mo => mo.Ignore())
.ReverseMap();
CreateMap<MediaItem, Domain.Models.Storage.MediaItem>()
.IncludeBase<SocialEntity, SocialDomainModel>()
.ReverseMap()
.IncludeBase<SocialDomainModel, SocialEntity>();
测试方法
[TestMethod]
public void MapMediaTest()
{
var m = MapperConfig.Mapper;
var entity = new MediaItem();
var entityToDomain = m.Map<Domain.Models.Storage.MediaItem>(entity);
Assert.IsTrue(entityToDomain != null);
}
如您所见,大约 20 秒后内存泛滥。
看起来自动映射器在某处配置错误,导致无限循环并导致StackOverflowException。
我的尝试
- 我尝试了每一个实体,结果总是一样。
- 在 5.1.1 和 6.0.2 之间切换了很多次。
- 尝试了很多不同的配置。
- 已将
HashSet集合切换为正常ICollections。
我在实体和域模型之间进行映射,没有使用投影/查询。
在映射之前检索每个实体,没有延迟加载。
请注意,我确实有 virtual 关键字与其他实体和类,并且默认情况下初始化每个集合。
我别无选择,除了放弃(不是这样)AutoMapper 以换取其他东西之外,我想不出还能做什么。我想要一些额外的见解,谢谢!
编辑Article 类。
/// <summary>
/// Used to store <see cref="Article"/> data.
/// </summary>
[ResourceKey("ARTICLE")]
public class Article : SocialEntity
{
/// <summary>
/// The main <see cref="Title"/> of this <see cref="Article"/>.
/// </summary>
public string Title { get; set; } = string.Empty;
/// <summary>
/// The content <see cref="Body"/> of this <see cref="Article"/>.
/// </summary>
public string Body { get; set; } = string.Empty;
/// <summary>
/// The <see cref="ShortDescription"/> of this <see cref="Article"/>.
/// </summary>
public string ShortDescription { get; set; } = string.Empty;
/// <summary>
/// The long <see cref="Description"/> of this <see cref="Article"/>.
/// </summary>
public string Description { get; set; } = string.Empty;
/// <summary>
/// The <see cref="DateTime"/> that the <see cref="Entity"/> will be available to use.
/// </summary>
public DateTime ExpiresOn { get; set; }
public virtual HashSet<Url> Sources { get; set; } = new HashSet<Url>();
public virtual HashSet<MediaItem> Media { get; set; } = new HashSet<MediaItem>();
public virtual HashSet<Tag> Tags { get; set; } = new HashSet<Tag>();
public virtual HashSet<Hobby> Hobbies { get; set; } = new HashSet<Hobby>();
}
【问题讨论】:
-
为什么需要
IncludeBase电话?我很确定这是默认设置。既然你打电话给ReverseMap,你为什么还要明确地创建反向地图 -
IncludeBase电话是我解决此问题的众多尝试之一。据我了解,ReverseMap调用确保双向映射已正确初始化,如果这些现在是多余的,我很乐意删除它们。 -
删除那些并且请确保也没有循环依赖。同样要进行故障排除,请从一个映射开始,然后继续添加更多映射,直到您发现问题的原因是哪个映射。
-
关于它,我很快就会得到结果。感谢您的帮助!
-
好吧,我已经隔离了大部分
CreateMapping方法,当我为Article类添加映射时,StackOverflowException开始重新出现。由于没有看到任何循环引用,因此我不知道如何继续。
标签: c# automapper