Как исправить автоматическое сопоставление таблицы объединения с ViewModel

#c# #entity-framework #asp.net-core #automapper

#c# #entity-framework #asp.net-core #автоматическое отображение

Вопрос:

Я использую AutoMapper 7.0.1 в проекте ASP CORE 2. Я пытаюсь сопоставить класс с таблицей соединений. Сопоставление объекта с моей моделью представления работает. Когда я ReverseMap(), таблица объединения имеет значение null и не сопоставляется обратно с объектом.

Причина этого в том, что я использую ViewModel для получения списка значений int для заполнения выбранных значений в списке множественного выбора.

Я просмотрел документацию AutoMapper, но, должно быть, мне чего-то не хватает в конфигурациях CreateMap. Я пытался использовать ForMember, но безуспешно.

Я также пытаюсь понять процесс выравнивания и разглаживания в ReverseMap()

     //Article.cs

    public class Article
    {
        public int ArticleId { get; set; }
        public string Title { get; set; }
        public virtual ICollection<ArticleGroup> ArticleGroups { get; set; } = new List<ArticleGroup>();
    }

    //Group.cs

    public class Group
    {
       public int GroupId { get; set; }
       public string GroupName { get; set; }
       public virtual ICollection<ArticleGroup> ArticleGroups { get; set; } = new List<ArticleGroup>();
    }

    //ArticleGroup.cs

    public class ArticleGroup
    {
       public int ArticleId { get; set; }
       public Article Article { get; set; }
       public int GroupId { get; set; }
       public Group Group { get; set; }
    }

    //ArticleFormView.cs

    public class ArticleFormView
    {
        public int ArticleId { get; set; }
        public string Title { get; set; }
        public virtual List<int> GroupIds { get; set; }
    }

    //Startup.cs
    ...

    AutoMapper.Mapper.Initialize(cfg =>
    {
       cfg.CreateMap<Article, ArticleFormView>()
          .ReverseMap()
       ;

       //Tried this as well removing ReverseMap() from above
       //cfg.CreateMap<ArticleFormView, Article>()
       //    .ForMember(a => a.ArticleGroups, opt =>
       //        opt.MapFrom(src =>
       //            src.GroupIds
       //        )
       //    )
       //;
    });

    ...
  
 //View Component
@model ArticleFormView

<div class="form-group">
    <label asp-for="Title" class="col-xs-1 control-label"></label>
    <div class="col-xs-11">
        <span asp-validation-for="Title" class="text-danger"></span>
        <input asp-for="Title" class="form-control">
    </div>
</div>
<div class="form-group">
    <label asp-for="GroupIds" class="col-xs-1 control-label"></label>
    <div class="col-xs-2">
        <select multiple="multiple" asp-for="GroupIds" asp-items="ViewBag.ListOfGroups" name="GroupIds[]" style="display:none"></select>
    </div>
</div>
  

Как мне настроить автоматическое отображение из списка int в ViewModel обратно в список ArticleGroup в объекте Article?

Ответ №1:

Я попытался воспроизвести ваш сценарий и в итоге AutoMapperConfigurationException заявил, что для GroupIds свойства ArticleFormView были найдены несопоставленные элементы. Таким образом, я также написал карту из домена:

 Mapper.Initialize(cfg =>
{
    cfg.CreateMap<Article, ArticleFormView>()
        .ForMember(articleFormView => articleFormView.GroupIds, opts =>
            opts.MapFrom(article => article.ArticleGroups.Select(articleGroup => articleGroup.GroupId)));

    cfg.CreateMap<ArticleFormView, Article>()
        .ForMember(article => article.ArticleGroups, opts =>
            opts.MapFrom(articleFormView => articleFormView.GroupIds.Select(id => new ArticleGroup
            {
                // Uncomment these two lines if you need them.
                //Article = new Article { Title = articleFormView.Title, ArticleId = articleFormView.ArticleId },
                //Group = new Group { GroupId = id },

                ArticleId = articleFormView.ArticleId,
                GroupId = id,
            })));
});
  

Имейте в виду, что, сопоставляя объект из статьи в представление формы, вы необратимо теряете данные. В предоставленной вами структуре представления формы существуют ограничения на то, какие элементы вы можете заполнить при обратном процессе сопоставления, просто потому, что у вас меньше данных для начала. Например, сохраняя только идентификаторы групп, вы теряете имена групп, поэтому при обратном сопоставлении вы не будете знать имя группы.

ReverseMap() не сработало, потому что AutoMapper не будет автоматически знать, как обрабатывать две разные коллекции разного типа и имени:

  • Article : коллекция, ArticleGroup называемая «ArticleGroups»
  • ArticleFormView : список int называемых «групповых идентификаторов»