【问题标题】:AutoMapper third level subcollection map with root propertiesAutoMapper 具有根属性的第三级子集合映射
【发布时间】:2020-11-28 06:41:27
【问题描述】:

我正在尝试将源子集合映射到有效的目标子集合。但我还需要在子集合上映射一些基本属性。我尝试使用 IncludeMembers,但没有运气。我试图找到一些将两种类型映射到一种的示例,但这似乎不适用于我的情况,因为大多数示例都是在我的都嵌套在同一个对象中时将两个不同类型的实例转换为一种。

我准备了一个单元测试来显示我的问题:

对象

public class FlatProduct
{
    public string Sku { get; set; }
    public int BrandId { get; set; }
    public int CategoryId { get; set; }
    public int ProductVersionId { get; set; }
    public int PriceLevelId { get; set; }
    public decimal Price { get; set; }
    public decimal RebatePrice { get; set; }
    public List<FlatProductInventory> FlatProductInventory { get; set; }


}

public class FlatProductInventory
{

    public int StockedLocationId { get; set; }
    public int StockedQty { get; set; }


}

public class Product
{
    public string Sku { get; set; }
    public int BrandId { get; set; }
    public int CategoryId { get; set; }
    public ProductVersion ProductVersion { get; set; }

}

public class ProductVersion
{

    public string Sku { get; set; }
    public int BrandId { get; set; }
    public int CategoryId { get; set; }
    public int ProductVersionId { get; set; }
    public ProductPrice ProductPrice { get; set; }
    public List<ProductInventory> ProductInventory { get; set; }

}

public class ProductPrice
{

    public string Sku { get; set; }
    public int BrandId { get; set; }
    public int CategoryId { get; set; }
    public int ProductVersionId { get; set; }
    public int PriceLevelId { get; set; }
    public decimal Price { get; set; }
    public decimal RebatePrice { get; set; }

}
public class ProductInventory
{

    public string Sku { get; set; }
    public int BrandId { get; set; }
    public int CategoryId { get; set; }
    public int ProductVersionId { get; set; }
    public int StockedLocationId { get; set; }
    public int StockedQty { get; set; }

}

映射/测试

public static void TestMapper()
    {
        var config = new MapperConfiguration(cfg => {
            cfg.CreateMap<FlatProduct, ProductPrice>();
            cfg.CreateMap<FlatProduct, ProductVersion>();
            cfg.CreateMap<FlatProduct, ProductInventory>();
            cfg.CreateMap<FlatProductInventory, ProductInventory>();
            cfg.CreateMap<FlatProduct, ProductVersion>()
                .ForMember(productVersion => productVersion.ProductPrice, flatProduct => flatProduct.MapFrom(fp => fp))
                .ForMember(productVersion => productVersion.ProductInventory, flatProduct => flatProduct.MapFrom(fp => fp))
                .ForMember(productVersion => productVersion.ProductInventory, flatProduct => flatProduct.MapFrom(fp => fp.FlatProductInventory));
            cfg.CreateMap<FlatProduct, Product>()
                .ForMember(product => product.ProductVersion, flatProduct => flatProduct.MapFrom(fp => fp));


        });

        IMapper mapper = config.CreateMapper();


        var flatProductExample = new FlatProduct
        {
            Sku = "ABC123",
            BrandId = 1,
            CategoryId = 1,
            ProductVersionId = 1,
            PriceLevelId = 1,
            Price = 12.99m,
            RebatePrice = 9.99m,
            FlatProductInventory = new List<FlatProductInventory>()
        {
            new FlatProductInventory()
            {
                StockedLocationId = 1,
                StockedQty = 33
            }
        }
        };

        var mappedProduct = mapper.Map<Product>(flatProductExample);

        Assert.Equal(flatProductExample.Sku, mappedProduct.ProductVersion.ProductInventory[0].Sku); //Fail
        Assert.Equal(flatProductExample.FlatProductInventory[0].StockedQty, mappedProduct.ProductVersion.ProductInventory[0].StockedQty); //Pass

    }

编辑

Xerillio 非常接近我需要的答案,事实上他的答案适用于 automapper 8 以下的版本。就我而言,我使用的是最新版本,因此我不得不稍微修改他的代码以使其正常工作。这里是:

var config = new MapperConfiguration(cfg => {
            cfg.CreateMap<FlatProduct, ProductPrice>();
            cfg.CreateMap<FlatProduct, ProductVersion>();
            cfg.CreateMap<FlatProduct, ProductInventory>();
            cfg.CreateMap<FlatProductInventory, ProductInventory>();
            cfg.CreateMap<FlatProduct, ProductVersion>()
                .ForMember(productVersion => productVersion.ProductPrice, flatProduct => flatProduct.MapFrom(fp => fp))
                .ForMember(productVersion => productVersion.ProductInventory, opt => opt.MapFrom((flatProduct, productVersion, i, context) => {
                    return flatProduct.FlatProductInventory

                        // Map using '<FlatProductInventory, ProductInventory>'
                        .Select(flatPInv => context.Mapper.Map<FlatProductInventory, ProductInventory>(flatPInv))
                        // Map (in-place by passing in the destination object)
                        // using '<FlatProduct, ProductInventory>'
                        .Select(destPInv => context.Mapper.Map<FlatProduct, ProductInventory>(flatProduct, destPInv))
                        // Now you've combined the mappings from FlatProduct and FlatProductInventory
                        .ToList();
                }));


            cfg.CreateMap<FlatProduct, Product>()
            .ForMember(product => product.ProductVersion, flatProduct => flatProduct.MapFrom(fp => fp));
                
            

        });

【问题讨论】:

    标签: c# .net-core automapper


    【解决方案1】:

    我的理解是,对于每个FlatProductInventory,您都希望拥有一个ProductInventory。但是,ProductInventory 还需要填充来自FlatProduct 的属性。

    您实际上已经在“将两种类型映射为一种”的正确轨道上,因此解决问题的一种方法如下:

    var config = new MapperConfiguration(cfg => {
        cfg.CreateMap<FlatProduct, ProductPrice>();
        cfg.CreateMap<FlatProduct, ProductVersion>();
        cfg.CreateMap<FlatProduct, ProductInventory>();
        cfg.CreateMap<FlatProductInventory, ProductInventory>();
        cfg.CreateMap<FlatProduct, ProductVersion>()
            .ForMember(productVersion => productVersion.ProductPrice, flatProduct => flatProduct.MapFrom(fp => fp))
            .ForMember(productVersion => productVersion.ProductInventory,
                opt => opt.ResolveUsing((flatProduct, productVersion, i, context) => {
                    return flatProduct.FlatProductInventory
                        // Map using '<FlatProductInventory, ProductInventory>'
                        .Select(flatPInv => context.Mapper.Map<FlatProductInventory, ProductInventory>(flatPInv))
                        // Map (in-place by passing in the destination object)
                        // using '<FlatProduct, ProductInventory>'
                        .Select(destPInv => context.Mapper.Map<FlatProduct, ProductInventory>(flatProduct, destPInv))
                        // Now you've combined the mappings from FlatProduct and FlatProductInventory
                        .ToList();
                })
            );
        cfg.CreateMap<FlatProduct, Product>()
            .ForMember(product => product.ProductVersion, flatProduct => flatProduct.MapFrom(fp => fp));
    });
    

    (可能存在语法错误,因为我没有通过 IDE 运行它。)

    【讨论】:

    • 谢谢你为我指明了正确的方向。它没有按原样工作,因为 AutoMapper 8 中不存在解析使用。我不得不修改我的代码以使其工作,但语法很好。非常感谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-25
    • 1970-01-01
    • 2019-12-06
    • 2019-08-02
    • 1970-01-01
    • 2021-02-27
    • 1970-01-01
    相关资源
    最近更新 更多