繁体   English   中英

在Automapper中映射集合

[英]Mapping Collections in Automapper

我正在使用Automapper克隆对象。 我有一个类,其中包含要以非标准方式处理的集合,我将在下面进行解释(我剥离了一些代码来突出显示特定问题):

public class CommunityModel 
{
    private readonly IUIManaer _uiMgr;
    private readonly IMapper _mapper;

    private ValidatedCollection<CommunityUserModel, string> _users;
    private int _communityIndex = -1;

    public CommunityModel( IUIManager uiMgr, IMapper mapper, IElementManager<CommunityUserModel, string> userMgr )
    {
        _uiMgr = uiMgr ?? throw new NullReferenceException( nameof(uiMgr) );
        _mapper = mapper ?? throw new NullReferenceException( nameof(mapper) );

        Users = new ValidatedCollection<CommunityUserModel, string>( userMgr );

    }

    public int CommunityIndex
    {
        get => _communityIndex;

        set
        {
            if (value < -1) value = -1;

            Set(ref _communityIndex, value);

            IsNew = value < 0;
        }
    }

    public ValidatedCollection<CommunityModel, string> Collection { get; set; }

    public ValidatedCollection<CommunityUserModel, string> Users
    {
        get => _users;

        set
        {
            ChangeTracker.RegisterCollection(value);

            SetAndValidate( ref _users, value );
        }
    }
}

ValidatedCollection <>是WPF的ObservableCollection的扩展。 CommunityIndex属性唯一地标识CommunityModel实例。 这使我可以通过EqualityComparison()扩展方法使用Automapper.Collection扩展。

我不希望Automapper初始化Users集合,因为它是在类构造函数中初始化的。 但是我希望将User集合的元素从源Users集合克隆到目标Users集合。

Collection集合包含CommunityModel对象的列表,包括具有Collection属性的实例(即Collection是一组同级CommunityModel实例)。 我希望Automapper初始化集合,并最终将源对象之外的所有CommunityModel兄弟复制到该集合中,然后将目标对象添加到该集合中(即,最后,集合将是一个集合同胞CommunityModel对象,而源CommunityModel被目标CommunityModel代替了)。

我的地图当前定义如下:

CreateMap<CommunityModel, CommunityModel>()
    .ForMember(dest=>dest.Users, opt=>opt.Ignore())
    .ForMember(dest=>dest.Collection, opt=>opt.Ignore()  )
    .EqualityComparison((x,y)=> x.CommunityIndex == y.CommunityIndex);

CreateMap<CommunityUserModel, CommunityUserModel>()
    .EqualityComparison((x,y) => x.UserIndex == y.UserIndex);

如果我不忽略()Users集合,则Automapper将初始化该集合,这将覆盖构造函数中设置的Users所需的配置,并在我的应用程序中的其他地方引起问题。 但是,如果忽略Ignore()Users集合,则永远不会将其元素从源克隆到目标。 我想要做的是没有Automapper初始化用户,但仍克隆内容。

如果我不忽略Collection集合,则会遇到无限循环和堆栈溢出的情况,我相信,因为克隆Collection的元素涉及到创建拥有Model属性的CommunityModel实例,该实例应该是对要创建的目标对象的引用,而是导致创建另一个相同的目标对象。 我想做的是让Automapper初始化Collection集合,但是>> not <<克隆源元素,我想稍后在AfterMap()调用中必须这样做。

我意识到这有些不可思议,但是我项目的总体设计导致了这些需求。

在Automapper中执行此操作的最佳方法是什么? 即使我正在克隆对象,我是否也应该考虑创建自定义值解析器,因此源和目标之间的属性名称相同?

我将描述如何解决我的问题,但我不会将其标记为答案,因为我对Automapper不够熟悉,无法知道我认为它在做什么,而实际上是在做什么。

当Automapper映射集合(即使已安装并激活Automapper.Collections库)时,似乎正在发生的事情是,即使源集合和目标集合中元素的类型可以是“不同”,也认为集合是“不同的”如果源和目标集合类型不同,则自动映射。

例如,如果源社区对象具有CommunityUsers的List <>:

public class Community
{
    public string Name { get; set; }
    public string SiteUrl { get; set; }
    public string LoginUrl { get; set; }
    public List<CommunityUser> Users { get; set; }
}

public class CommunityUser
{
    public string UserID { get; set; }
    public string VaultKeyName { get; set; }
}

并且您想要将其映射到目标对象,如下所示:

public class CommunityModel
{
    // omitting constructor, which contains logic to 
    // initialize the Users property based on constructor arguments

    public string Name {get;set;}
    public string LoginUrl {get;set;}
    public string SiteUrl {get;set;}
    public ValidatedCollection<CommunityUserModel, string> Users
    { get; set;}
}

public class CommunityUserModel 
{
    public string UserID {get; set;}
    public string VaultKeyName {get;set;}
}

即使所有属性名称都可以由Automapper识别,并且两个Users集合都是IEnumerable,但是两个集合类型不同的事实显然会使Automapper将这些集合视为“不同”。

显然,这意味着Automapper.Collections的添加/删除/复制逻辑不会被使用,即使存在也是如此。 而是,Automapper尝试创建(在本例中)ValidatedCollection的实例,从源对象集合填充它,然后将其分配给目标对象集合。

如果ValidatedCollection <>没有必需的构造方法参数,那很好。 但是,如果这样做,它将失败。 我的情况就是这样。

我的解决方法是在Mapper定义中执行此操作:

CreateMap<Community, CommunityModel>()
    .ForMember(dest=>dest.Users, opt=> opt.Ignore())
    .AfterMap( ( src, dest, rc ) =>
    {
        foreach( var srcUser in src.Users )
        {
            dest.Users.Add(rc.Mapper.Map<CommunityUserModel>(srcUser));
        }
    } );

这使Automapper不会对目标Users属性(在CommunityModel构造函数中初始化)进行任何操作,并在完成“自动”映射后在源User对象上进行映射。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM