C# 具有根属性的AutoMapper第三级子集合映射

C# 具有根属性的AutoMapper第三级子集合映射,c#,.net-core,automapper,C#,.net Core,Automapper,我正在尝试将源子集合映射到有效的目标子集合。但是我还需要映射子集合上的一些基本属性。我试过了,但没有成功。我试图找到一些将两种类型映射为一种类型的示例,但这似乎不适用于我的情况,因为大多数示例都是将两个不同类型的实例转换为一个,而我的实例都嵌套在同一个对象中 我准备了一个单元测试来说明我的问题: 对象 public class FlatProduct { public string Sku { get; set; } public int BrandId { get; set;

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

我准备了一个单元测试来说明我的问题:

对象

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; }

}
公共类平面产品
{
公共字符串Sku{get;set;}
public int BrandId{get;set;}
public int CategoryId{get;set;}
public int ProductVersionId{get;set;}
public int PriceLevelId{get;set;}
公共十进制价格{get;set;}
公共十进制重新调整价格{get;set;}
公共列表FlatProductInventory{get;set;}
}
公共类库存
{
public int StockedLocationId{get;set;}
public int StockedQty{get;set;}
}
公共类产品
{
公共字符串Sku{get;set;}
public int BrandId{get;set;}
public int CategoryId{get;set;}
公共产品版本ProductVersion{get;set;}
}
公共类产品版本
{
公共字符串Sku{get;set;}
public int BrandId{get;set;}
public int CategoryId{get;set;}
public int ProductVersionId{get;set;}
公共产品价格产品价格{get;set;}
公共列表ProductInventory{get;set;}
}
公共类产品价格
{
公共字符串Sku{get;set;}
public int BrandId{get;set;}
public int CategoryId{get;set;}
public int ProductVersionId{get;set;}
public int PriceLevelId{get;set;}
公共十进制价格{get;set;}
公共十进制重新调整价格{get;set;}
}
公共类产品目录
{
公共字符串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

    }
publicstaticvoidtestmapper()
{
var config=new-MapperConfiguration(cfg=>{
CreateMap();
CreateMap();
CreateMap();
CreateMap();
cfg.CreateMap()
.FormMember(productVersion=>productVersion.ProductPrice,flatProduct=>flatProduct.MapFrom(fp=>fp))
.FormMember(productVersion=>productVersion.ProductInventory,flatProduct=>flatProduct.MapFrom(fp=>fp))
.FormMember(productVersion=>productVersion.ProductInventory,flatProduct=>flatProduct.MapFrom(fp=>fp.FlatProductInventory));
cfg.CreateMap()
.ForMember(product=>product.ProductVersion,flatProduct=>flatProduct.MapFrom(fp=>fp));
});
IMapper mapper=config.CreateMapper();
var flatProductExample=新的FlatProduct
{
Sku=“ABC123”,
BrandId=1,
类别ID=1,
ProductVersionId=1,
PriceLevelId=1,
价格=1299万美元,
再加热温度=9.99米,
FlatProductInventory=新列表()
{
新产品目录()
{
StockedLocationId=1,
库存数量=33
}
}
};
var mappedProduct=mapper.Map(flatProductExample);
Assert.Equal(flatProductExample.Sku,mappedProduct.ProductVersion.ProductInventory[0].Sku);//失败
Assert.Equal(flatProductExample.FlatProductInventory[0].StockedQty,mappedProduct.ProductVersion.ProductInventory[0].StockedQty);//通过
}
编辑 Xerilio非常接近我需要的答案,事实上他的答案将适用于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));
                
            

        });
var config=new-MapperConfiguration(cfg=>{
CreateMap();
CreateMap();
CreateMap();
CreateMap();
cfg.CreateMap()
.FormMember(productVersion=>productVersion.ProductPrice,flatProduct=>flatProduct.MapFrom(fp=>fp))
.FormMember(productVersion=>productVersion.ProductInventory,opt=>opt.MapFrom((flatProduct,productVersion,i,context)=>{
返回flatProduct.FlatProductInventory
//使用“”映射
.Select(flatPInv=>context.Mapper.Map(flatPInv))
//映射(通过传入目标对象就地)
//使用“”
.Select(destPInv=>context.Mapper.Map(flatProduct,destPInv))
//现在您已经组合了FlatProduct和FlatProductInventory的映射
.ToList();
}));
cfg.CreateMap()
.ForMember(product=>product.ProductVersion,flatProduct=>flatProduct.MapFrom(fp=>fp));
});

我的理解是,对于每个
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));
});
var config=new-MapperConfiguration(cfg=>{
CreateMap();
CreateMap();
CreateMap();
CreateMap();
cfg.CreateMap()
.FormMember(productVersion=>productVersion.ProductPrice,flatProduct=>flatProduct.MapFrom(fp=>fp))
.FormMember(productVersion=>productVersion.ProductInventory,
opt=>opt.Resol