簡體   English   中英

枚舉與其 integer 值之間的 AutoMapper 映射因 ReverseMap 而失敗

[英]AutoMapper mapping between enum and its integer values fails with ReverseMap

該應用程序是使用 DDD 方法構建的,具有一組單獨的持久性模型。 我調用了數據庫 object 或 dbo:

public class ParentDbo
{
    public int ParentId { get; set; }
    public int TypeId { get; set; }
}

public class ChildDbo
{
    public int ChildId { get; set; }
    public ParentDbo Parent { get; set; }
    public int RetryNumber { get; set; }
}

我們有一個簡單的 model 來查看:父子關系。 RetryNumber表示數據庫中的枚舉值。


在檢索數據時,它首先使用 Dapper 查詢數據庫,並使用它的splitOn功能將 map 數據插入其中。 這部分無關緊要,但為了完整起見,我還是會展示它:

const string sql = "SELECT * FROM XXX ....";

using (var cnt = _dbConnectionFactory.CreateConnection())
{
    var childDbos = await cnt.QueryAsync<ChildDbo, ParentDbo, ChildDbo>(
        sql: sql,
        map: (childDbo, parentDbo) =>
        {
            childDbo.Parent = parentDbo;
            return childDbo;
        },
        splitOn: "ParentId"
    );
}

Dapper 的局限性在於它不能將 map 數據傳輸到私有復雜對象。 這主要是我必須有兩套模型的原因。 我想使用私有設置器和其他技術將數據和邏輯封裝在域模型中。

這是我的域模型:

public class Parent
{
    public int Id { get; private set; }
    public int TypeId { get; private set; }
    
    public Parent(int parentId, int typeId)
    {
        // Validations
        
        this.Id = parentId;
        this.TypeId = typeId;
    }
}

public class Child
{
    public int Id { get; private set; }
    public Parent Parent { get; private set; }
    public Attempt Attempt { get; private set; }
    
    public Child(int childId, Parent parent, Attempt attempt)
    {
        // Validations
        
        this.Id = childId;
        this.Parent = parent;
        this.Attempt = attempt;
    }
}

對於域模型,我不想要公共設置器和無參數構造器。

Attempt是帶有 integer 支持值的枚舉:

public enum Attempt
{
    Original = 1,
    FirstRetry = 2,
    SecondRetry = 3,
    LastRetry = 4
}

最后,我想在 Dbos 和域模型之間使用 AutoMapper 到 map。 這是映射:

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<Child, ChildDbo>()
            .ForMember(dest => dest.ChildId, opts => opts.MapFrom(src => src.Id))
            .ForMember(dest => dest.RetryNumber, opts => opts.MapFrom(src => (int)src.Attempt))
            .ReverseMap();
        
        CreateMap<Parent, ParentDbo>()
            .ForMember(dest => dest.ParentId, opts => opts.MapFrom(src => src.Id))
            .ReverseMap();
    }
}

我想要雙向映射,所以我使用ReverseMap()


.Net Fiddle 演示: https://dotnetfiddle.net/saEHWd

它將域模型映射到 dbo 沒有問題:

在此處輸入圖像描述

但它的反向,從 dbo 到域模型的映射,正在拋出異常:

未處理的異常。 System.ArgumentException:Program+Child 需要有一個帶有 0 個參數或只有可選參數的構造函數。 AutoMapper.Mapper.MapCore[TSource,TDestination](TSource source, Tdestination destination, ResolutionContext context, Type sourceType, Type destinationType, IMemberMap memberMap) 中的 lambda_method18(Closure, Object, Child, ResolutionContext ) 中的(參數“類型”)。 Mapper.Map[TSource,Tdestination](TSource source, Tdestination destination) at AutoMapper.Mapper.Map[Tdestination](Object source) at Program.Main()


我試圖刪除枚舉屬性並且一切正常,所以我很確定這是有問題的枚舉映射。

據我在您的小提琴中看到的,您正在嘗試從ChildDboParent的 map 並且沒有針對它的映射設置。 將映射代碼更改為:

var child2 = mapper.Map<Child>(childDbo);

由於第三個Child的 ctor 參數和源屬性名稱不匹配,因此將 map 更改為:

CreateMap<Child, ChildDbo>()
    .ForMember(dest => dest.ChildId, opts => opts.MapFrom(src => src.Id))
    .ForMember(dest => dest.RetryNumber, opts => opts.MapFrom(src => (int)src.Attempt))
    .ReverseMap()
    .ConstructUsing((dbo, ctx) => new Child(dbo.ChildId, ctx.Mapper.Map<Parent>(dbo.Parent), (Attempt)dbo.RetryNumber));

這里

或者將第三個Child的 ctor 參數重命名為retryNumber

public Child(int childId, Parent parent, Attempt retryNumber)

這里

或使用ForCtorParam

CreateMap<Child, ChildDbo>()
    .ForMember(dest => dest.ChildId, opts => opts.MapFrom(src => src.Id))
    .ForMember(dest => dest.RetryNumber, opts => opts.MapFrom(src => (int)src.Attempt))
    .ReverseMap()
    .ForCtorParam("attempt", opt => opt.MapFrom(dbo => dbo.RetryNumber))

在這里

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM