繁体   English   中英

AutoMapper 使用数组列表的嵌套属性映射

[英]AutoMapper to Map with nested property of List of array

我有一个 A 类,我需要用 C 类映射

public class A{
   public string Name {get; set;}
   public List<B> Address {get; set;}}


public class B{
    public string streetName{get; set;}
    public int Number {get; set;}}

我需要将此映射到 C 类

public class C{
    public int id{get;set;}
    public List<MapAddressData> MapAddressData{get; set;}
    public DateTime DateCreated {get; set;}}

public class MapAddressData{
   public string Name {get; set;}
   public string streetName {get; set;}
   public int Number{get; set;}}

所以我需要使用自动映射器将 A 类中的地址列表映射到 C 类中的 MapAddressData 列表。我不明白如何使用 for 循环进行映射,因为对于特定名称,我们有很多地址,n 必须映射对C类中的'MapAddressData'类一一进行。有没有办法实现这一点?

我不确定是否有更清洁的方法可以做到这一点,但您可以像这样配置 AutoMapper:

cfg.CreateMap<A, C>()
    .BeforeMap((src, _, ctx) => ctx.Options.Items[$"__{nameof(A)}"] = src)
    .ForMember(dst => dst.MapAddressData, mo => mo.MapFrom(src => src.Address));

cfg.CreateMap<B, MapAddressData>()
    .ForMember(dst => dst.Name, mo => mo.MapFrom(new MapAddressNameResolver()));

使用.BeforeMap我们使用键"__A"将源值存储在映射上下文项集合中。

接下来,我们告诉 AutoMapper 它应该使用源对象的Address属性将MapAddressData映射到目标对象。

然后我们在BMapAddressData之间创建一个映射。 对于目标对象的Name属性,我们使用自定义解析器: MapAddressNameResolver来检索值:

private class MapAddressNameResolver : IValueResolver<B, MapAddressData, string>
{
    public string Resolve(B source, MapAddressData destination, string destMember, ResolutionContext context)
    {
        if (context.Options.Items.TryGetValue($"__{nameof(A)}", out var parent) 
                && parent is A sourceParent)
        {
            return sourceParent.Name;
        }
        throw new InvalidOperationException("Address cannot be mapped to MapAddressData indepdendently of A to C.");
    }
}

这会查看映射上下文项集合,并尝试检索针对键"__A"存储的值。 如果它确实是A的一个实例,我们返回它的Name属性。

如果其中任何一个不正确,我们会抛出一个异常,以便我们知道如果将来有人尝试在其他上下文中使用此映射而不添加适当的支持,则此映射已失败。


完整示例

public static void TestMethod()
{

    var mapperConfig = new MapperConfiguration(cfg =>
    {
        cfg.CreateMap<A, C>()
            .BeforeMap((src, _, ctx) => ctx.Options.Items[$"__{nameof(A)}"] = src)
            .ForMember(dst => dst.MapAddressData, mo => mo.MapFrom(src => src.Address));

        cfg.CreateMap<B, MapAddressData>()
            .ForMember(dst => dst.Name, mo => mo.MapFrom(new MapAddressNameResolver()));
    });
    var mapper = mapperConfig.CreateMapper();

    var sourceObject = new A()
    {
        Name = "bob",
        Address = new List<B>()
    {
        new B()
        {
            Number = 5,
            streetName = "bob street"
        },
        new B()
        {
            Number = 125,
            streetName = "somewhere street"
        }
    }
    };

    var mappedObject = mapper.Map<C>(sourceObject);
}

private class MapAddressNameResolver : IValueResolver<B, MapAddressData, string>
{
    public string Resolve(B source, MapAddressData destination, string destMember, ResolutionContext context)
    {
        if (context.Options.Items.TryGetValue($"__{nameof(A)}", out var parent) && parent is A sourceParent)
        {
            return sourceParent.Name;
        }
        throw new InvalidOperationException("Address cannot be mapped to MapAddressData indepdendently of A to C.");
    }
}

例如,您有 A 类的数据,例如

名称=用户 1

地址1

街道名称 = 街道名称 1 编号 = 编号 1

地址2

街道名称 = 街道名称 2 编号 = 编号 2

地址3

街道名称 = 街道名称 3 编号 = 编号 3

对于多个名称,您必须进行嵌套循环来访问 A 类对象中的每个数据,同时考虑我们有MapAddressData类的对象作为 mappedAddress。

foreach(var item from ClassAObject)
{
   mappedAddress.Name = item.Name;
   foreach(var address from item.Address)
   {
      mappedAddress.streetName = address.streetName;
      mappedAddress.Number= address.Number;
      >> Here you will be adding this mappedAddress objcect in mappedAddress from class C.

   }
}

附加代码示例只是为了获得更多说明

暂无
暂无

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

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