使用AutoMapper添加、更新和删除列表中的项目 [英] Use AutoMapper for adding, updating and removing items in List

查看:0
本文介绍了使用AutoMapper添加、更新和删除列表中的项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在需要删除、添加或更新的情况下,AutoMapper是否没有更新嵌套列表的本机方法?

我在带有EF Core的ASP.NET Core应用程序中使用AutoMapper将API资源映射到我的模型。这在我的大部分应用程序中都运行得很好,但我对更新映射嵌套列表的解决方案不满意,在该列表中列出的实例需要持久化。我不想覆盖现有列表,我想删除传入资源中不再存在的实例,添加新实例,并更新现有实例。

型号:

public class MainObject
{
    public int Id { get; set; }
    public List<SubItem> SubItems { get; set; }
    
}

public class SubItem
{
    public int Id { get; set; }
    public int MainObjectId { get; set; }
    public MainObject MainObject { get; set; }
    public double Value { get; set; }
}

资源:

public class MainObjectResource
{
    public int Id { get; set; }
    public ICollection<SubItemResource> SubItems { get; set; }
    
}

public class SubItemResource
{
    public int Id { get; set; }
    public double Value { get; set; }
}

控制器:

public class MainController : Controller
{
    private readonly IMapper mapper;
    private readonly IMainRepository mainRepository;
    private readonly IUnitOfWork unitOfWork;

    public MainController(IMapper mapper, IMainRepository mainRepository, IUnitOfWork unitOfWork)
    {
        this.mapper = mapper;
        this.mainRepository = mainRepository;
        this.unitOfWork = unitOfWork;
    }

    [HttpPut("{id}")]
    public async Task<IActionResult> UpdateMain(int id, [FromBody] MainObjectResource mainObjectResource)
    {
        MainObject mainObject = await mainRepository.GetMain(id);
        mapper.Map<MainObjectResource, MainObject>(mainObjectResource, mainObjectResource);
        await unitOfWork.CompleteAsync();

        return Ok(); 
    }
}

映射配置文件:

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<MainObject, MainObjectResource>();
        CreateMap<SubItem, SubItemResource>();

        CreateMap<MainObject, MainObjectResource>().ReverseMap()
        .ForMember(m => m.Id, opt => opt.Ignore())
        .ForMember(m => m.SubItems, opt => opt.Ignore())
        .AfterMap((mr, m) => {
                //To remove
                List<MainObject> removedSubItems = m.SubItems.Where(si => !mr.SubItems.Any(sir => si.Id == sir.Id)).ToList();
                foreach (SubItem si in removedSubItems)
                    m.SubItems.Remove(si);
                //To add
                List<SubItemResource> addedSubItems = mr.SubItems.Where(sir => !m.SubItems.Any(si => si.Id == sir.Id)).ToList();
                foreach (SubItemResource sir in addedSubItems)
                    m.SubItems.Add( new SubItem {
                        Value = sir.Value,
                    });
                // To update
                List<SubItemResource> updatedSubItems = mr.SubItems.Where(sir => m.SubItems.Any(si => si.Id == sir.Id)).ToList();
                SubItem subItem = new SubItem();
                foreach (SubItemResource sir in updatedSubItems)
                {
                    subItem = m.SubItems.SingleOrDefault(si => si.Id == sir.Id);
                    subItem.Value = sir.Value;
                }
            });
    }
}

我在这里做的是一个定制映射,但我觉得这是一个非常通用的情况,我希望AutoMapper能够通过某种扩展来处理它。我见过一些映射配置文件使用自定义映射(.AfterMap)的示例,但实际的映射是由AutoMapper的静态实例完成的。我不确定这是否适合我通过依赖项注入使用AutoMapper:我不是一个有经验的程序员,但在我看来这并不合理。

推荐答案

多亏了Ivan Stoev,我开始关注AutoMapper.Collection,这确实是我希望找到的扩展。在实现之后,我的列表会按照我的意愿进行更新。该配置在我的使用中非常简单,因为我只需要指定我的对象的ID。

我的启动配置更改为:

using AutoMapper;
using AutoMapper.EquivalencyExpression;
[....]
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAutoMapper(cfg => {
                cfg.AddCollectionMappers();
                });
        }
[....]

和我的映射配置文件:

    CreateMap<SubItem, SubItemResource>().ReverseMap()
        .EqualityComparison((sir, si) => sir.Id == si.Id);

这篇关于使用AutoMapper添加、更新和删除列表中的项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆