Arhn - архитектура программирования

Преобразование списка словарей в список классов

Я играл с API Team Foundation Server 2018. Я могу подключиться к API и получить список рабочих элементов в форме List<IDictionary<string, object>>, но этот формат не очень удобен. Данные нужно немного помассировать, чтобы они были более удобными для использования и дружественными к циклам.

Например, я хочу взять этот формат данных и отобразить его в сетке данных. Я создал простое приложение WPF без каких-либо наворотов для решения этой проблемы.

В этом примере есть переменная с именем data, которая была создана так, чтобы напоминать данные из моей системы TFS.

На MainWindow.xaml все, что я создал, это DataGrid с именем DataGrid. В MainWindow.xaml.cs я намереваюсь сопоставить List<WorkItem> с этой DataGrid.

MainWindow.xaml

<Window x:Class="AutoMapperExample.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d" Title="AutoMapper Example" Height="350" Width="525" ResizeMode="CanResizeWithGrip">
    <Grid>
        <DataGrid x:Name="DataGrid" />
    </Grid>
</Window>

MainWindow.xaml.cs

namespace AutoMapperExample.Views {
    using System.Collections.Generic;
    using System.Windows;
    using AutoMapper;

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();

            var data = new List<IDictionary<string, object>> {
                new Dictionary<string, object> {
                    {"System.Id", 1}, {"System.State", "Open"}, {"System.TeamProject", "Project1"}, {"System.Title", "First Work Item Title for Project 1"}
                },
                new Dictionary<string, object> {
                    {"System.Id", 2}, {"System.State", "Closed"}, {"System.TeamProject", "Project2"}, {"System.Title", "Work Item Title for Project 2"}
                },
                new Dictionary<string, object> {
                    {"System.Id", 3}, {"System.State", "Closed"}, {"System.TeamProject", "Project1"}, {"System.Title", "Second Work Item Title for Project 1"}
                }
            };

            DataGrid.ItemsSource = ParseData(data);
        }

        private IEnumerable<WorkItem> ParseData(List<IDictionary<string, object>> data) {
            Mapper.Initialize(cfg => {
                //                cfg.CreateMap<List<IDictionary<string,object>>, List<WorkItem>>();
                //                cfg.CreateMap<IDictionary<string, object>, WorkItem>();
                //                cfg.RecognizePrefixes("System.");
                //                cfg.ReplaceMemberName("System.", string.Empty);
            });

            var workItems = Mapper.Map<List<WorkItem>>(data);

            return workItems;
        }
    }

    public class WorkItem {
        public int Id { get; set; }

        public string Project { get; set; }

        public string State { get; set; }

        public string Title { get; set; }
    }
}

Обратите внимание, что ключи всех словарей также имеют префикс System..

Я решил использовать AutoMapper для решения этой проблемы, и полученный список содержит правильное количество элементов, но все свойства имеют значения по умолчанию или нулевые. В примере есть прокомментированный код, который показывает, что я пробовал, но все они имеют одинаковый результат.

Является ли AutoMapper решением этой проблемы? Если да, то какие настройки мне нужно правильно преобразовать в мой List<WorkItem>


  • Понижение без комментариев никому не поможет. Пожалуйста, скажите, что не так, чтобы я мог это исправить. 24.01.2018
  • Я не уверен, почему отрицательный голос, но это кажется проблемой при создании вашего типа WorkItem из List<IDictionary<string,object> с помощью AutoMapper. Более простой вопрос, на который нужно ответить, будет заключаться в том, как мне ввести List<IDictionary<string,object> в этот класс и показать некоторые примеры данных - что-то, что любой может запустить, не запустив доступ к TFS. Кроме того, было бы проще, если бы ваш код можно было просто скопировать, вставить и заменить моими учетными данными и экземпляром TFS - MCVE 25.01.2018
  • Я прочитал ветку, и голосование против может быть связано с тем, что вы могли бы добиться аналогичных результатов, получая все назначенные рабочие элементы с помощью простых запросов в TFS, но вы правы, что по этому вопросу также необходим комментарий. Я голосую за него сейчас, поэтому вопрос остается актуальным. 25.01.2018
  • Хорошо, это справедливо. Я собираюсь изменить этот вопрос тогда. Я собираюсь рассказать о том, почему данные, которые я получаю, имеют форму List<IDictionary<string,object>, но я сделаю это примерно так, как предложил @DaveShaw. Преобразование List<IDictionary<string,object> в список классов и отображение его в DataGrid. 25.01.2018

Ответы:


1

Вы можете обмануть промежуточную сериализацию. Примените атрибуты [JsonProperty] к вашей модели:

public class WorkItem
{
    [JsonProperty("System.Id")]
    public int Id { get; set; }

    [JsonProperty("System.TeamProject")]
    public string Project { get; set; }

    [JsonProperty("System.State")]
    public string State { get; set; }

    [JsonProperty("System.Title")]
    public string Title { get; set; }
}

затем реализуйте преобразователь пользовательского типа, используя сериализатор Newtonsoft.Json под капотом:

public class WorkItemTypeConverter : ITypeConverter<IDictionary<string, object>, WorkItem>
{
    public WorkItem Convert(IDictionary<string, object> source, WorkItem destination, ResolutionContext context)
    {
        var json = JsonConvert.SerializeObject(source);

        return JsonConvert.DeserializeObject<WorkItem>(json);
    }
}

и укажите его использование в конфигурации AutoMapper:

Mapper.Initialize(cfg =>
{
    cfg.CreateMap<IDictionary<string, object>, WorkItem>()
        .ConvertUsing<WorkItemTypeConverter>();
});

Я основывал свой ответ на этом Дарина Димитрова.

10.08.2019
  • Интересный. Мне это решение нравится намного больше, чем то, что у меня получилось. Я прибегнул к циклическому просмотру возвращенного словаря и удалению System. от Ключа. Так ненавидел это решение. 15.08.2019
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..