Нет ли в AutoMapper собственного подхода к обновлению вложенных списков, в которых необходимо удалить экземпляры, добавить или обновить ?
Здравствуйте, я использую AutoMapper в своем приложении ASP.Net Core с EF Core для сопоставления ресурсов 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 через внедрение зависимостей: я не опытный программист, но мне это не кажется правильным.