如何在不覆盖值的情况下映射列表
How to map lists without overwriting values
我有一个包含两种不同对象类型的对象,我试图将它映射到另一个包含单个列表的对象。
在这个简单的最小可重现示例中,我创建了一个动物园 class,其中包含一个动物列表,这是目的地。来源是 MammelHouse class,其中包含猪和牛对象的列表。
我的问题是,当我尝试将猪添加到列表中时,它覆盖了已经写入的奶牛。我需要将这两个对象添加到此列表中。
我目前的解决方案是单独映射每个对象类型,然后将它们添加到主对象,因为我的实际应用程序目前有十种不同的类型,这不是最佳解决方案。我希望有一种方法可以直接使用 automapper 解决这个问题。
当前映射尝试
public class MappingResourceZoo : Profile
{
public MappingResourceZoo()
{
CreateMap<MammalHouse, Zoo>()
.ForMember(dest => dest.Animals, opt => opt.MapFrom(src => src.Cows))
.ForMember(dest => dest.Animals, opt => opt.MapFrom(src => src.Pigs));
CreateMap<Cow, Animal>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Species));
CreateMap<Pig, Animal>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Species));
}
}
这个映射的问题是当猪被映射时,奶牛被覆盖了。所以测试失败。,
测试
[Fact]
public void TestsConcatAddress()
{
var src = new MammalHouse()
{
Cows = new List<Cow>()
{
new Cow() {Species= "Chocolate cow"},
new Cow() {Species= "Vanilla cow"}
},
Pigs = new List<Pig>()
{
new Pig() { Species= "Bacon"},
new Pig() { Species= "Sausage"}
}
};
var config = new MapperConfiguration(cfg => cfg.AddProfile<MappingResourceZoo>());
var mapper = config.CreateMapper();
var response = mapper.Map<Zoo>(src);
response.Animals.Should().NotBeNull().And.HaveCount(4); ;
}
这是您测试乐趣的模型。这两个模型来自第三方系统,无法更改。
// The Zoo model comes from third party api 1
public class Zoo
{
public List<Animal> Animals { get; set; }
}
public class Animal
{
public string Name { get; set; }
}
// The mammal model comes from third party api Two.
public class MammalHouse
{
public List<Cow> Cows { get; set; }
public List<Pig> Pigs { get; set; }
}
public class Cow
{
public string Species{ get; set; } = "cow";
}
public class Pig
{
public string Species{ get; set; } = "pig";
}
我看过的
- 添加 AfterMap 这并不是正确的方向,因为我实际上有两个以上。
- 目前正在尝试使用自定义映射器使其工作,但它也无法正常工作,因为我无法将映射器对象传递给它。
根据评论更新
从评论中建议显然不允许使用 Concat。
CreateMap<MammalHouse, Zoo>()
.ForMember(dest => dest.Animals, opt => opt.MapFrom(src => src.Cows.Concat(src.Pigs)));
也试过添加范围,但还是不行,因为牛和猪不是同一种类型
opt.MapFrom(src => src.Cows.AddRange(src.Pigs)));
在Cow
和Pig
中添加一个普通的interface
IMammel
然后使用Concat
型号
public interface IMammel
{
}
public class Animal
{
public string Name { get; set; }
}
public class Pig : IMammel
{
public string Species { get; set; } = "pig";
}
public class Cow : IMammel
{
public string Species { get; set; } = "cow";
}
AutoMapper 配置
public class MappingResourceZoo : Profile
{
public MappingResourceZoo()
{
CreateMap<Cow, Animal>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Species));
CreateMap<Pig, Animal>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Species));
CreateMap<MammalHouse, Zoo>()
.ForMember(dest => dest.Animals, opt => opt.MapFrom(src => src.Cows.Concat<IMammel>(src.Pigs)));
}
}
我有一个包含两种不同对象类型的对象,我试图将它映射到另一个包含单个列表的对象。
在这个简单的最小可重现示例中,我创建了一个动物园 class,其中包含一个动物列表,这是目的地。来源是 MammelHouse class,其中包含猪和牛对象的列表。
我的问题是,当我尝试将猪添加到列表中时,它覆盖了已经写入的奶牛。我需要将这两个对象添加到此列表中。
我目前的解决方案是单独映射每个对象类型,然后将它们添加到主对象,因为我的实际应用程序目前有十种不同的类型,这不是最佳解决方案。我希望有一种方法可以直接使用 automapper 解决这个问题。
当前映射尝试
public class MappingResourceZoo : Profile
{
public MappingResourceZoo()
{
CreateMap<MammalHouse, Zoo>()
.ForMember(dest => dest.Animals, opt => opt.MapFrom(src => src.Cows))
.ForMember(dest => dest.Animals, opt => opt.MapFrom(src => src.Pigs));
CreateMap<Cow, Animal>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Species));
CreateMap<Pig, Animal>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Species));
}
}
这个映射的问题是当猪被映射时,奶牛被覆盖了。所以测试失败。,
测试
[Fact]
public void TestsConcatAddress()
{
var src = new MammalHouse()
{
Cows = new List<Cow>()
{
new Cow() {Species= "Chocolate cow"},
new Cow() {Species= "Vanilla cow"}
},
Pigs = new List<Pig>()
{
new Pig() { Species= "Bacon"},
new Pig() { Species= "Sausage"}
}
};
var config = new MapperConfiguration(cfg => cfg.AddProfile<MappingResourceZoo>());
var mapper = config.CreateMapper();
var response = mapper.Map<Zoo>(src);
response.Animals.Should().NotBeNull().And.HaveCount(4); ;
}
这是您测试乐趣的模型。这两个模型来自第三方系统,无法更改。
// The Zoo model comes from third party api 1
public class Zoo
{
public List<Animal> Animals { get; set; }
}
public class Animal
{
public string Name { get; set; }
}
// The mammal model comes from third party api Two.
public class MammalHouse
{
public List<Cow> Cows { get; set; }
public List<Pig> Pigs { get; set; }
}
public class Cow
{
public string Species{ get; set; } = "cow";
}
public class Pig
{
public string Species{ get; set; } = "pig";
}
我看过的
- 添加 AfterMap 这并不是正确的方向,因为我实际上有两个以上。
- 目前正在尝试使用自定义映射器使其工作,但它也无法正常工作,因为我无法将映射器对象传递给它。
根据评论更新
从评论中建议显然不允许使用 Concat。
CreateMap<MammalHouse, Zoo>()
.ForMember(dest => dest.Animals, opt => opt.MapFrom(src => src.Cows.Concat(src.Pigs)));
也试过添加范围,但还是不行,因为牛和猪不是同一种类型
opt.MapFrom(src => src.Cows.AddRange(src.Pigs)));
在Cow
和Pig
中添加一个普通的interface
IMammel
然后使用Concat
型号
public interface IMammel
{
}
public class Animal
{
public string Name { get; set; }
}
public class Pig : IMammel
{
public string Species { get; set; } = "pig";
}
public class Cow : IMammel
{
public string Species { get; set; } = "cow";
}
AutoMapper 配置
public class MappingResourceZoo : Profile
{
public MappingResourceZoo()
{
CreateMap<Cow, Animal>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Species));
CreateMap<Pig, Animal>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Species));
CreateMap<MammalHouse, Zoo>()
.ForMember(dest => dest.Animals, opt => opt.MapFrom(src => src.Cows.Concat<IMammel>(src.Pigs)));
}
}