簡體   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