Как экспортировать данные из списка в файлы CSV с другим форматом CSV - PullRequest
0 голосов
/ 13 сентября 2018

Мне нужно загрузить отчет в другую другую систему, система имеет собственную предопределенную структуру отчетов, которые они принимают.Эти отчеты в нашей системе генерируются на основе кода, который выбирает пользователь.

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

Заголовки и количество столбцов в файлах CSV отличаются в зависимости от типа кода, который выбирает пользователь.

Как я подошел:

public ActionResult GetFileResult(string code)
{
    var record = new Employee().GetEmployeeData(code);
    var csvResult = GetCSVResult(code, record);

    return csvResult;
}

private string GetCSVResult(string code, List<Employee> employees)
{
    //How can i model here the GetCSVResult to convert 
    //the List of employees to CSV with refrence to code

    //the value on the code will determine which format to used for the csv result.
}

Здесь, вМетод GetCSVResult. Я могу использовать несколько операторов if или switch-case для вызова другого метода, который имеет собственную реализацию преобразования списка в CSV, но есть как минимум 20 различных конфигураций CSV, которые приведут к нескольким операторам if иЛот метода.

public class Employee
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string DOB { get; set; }
    public string StartDate { get; set; }
    public string SSN { get; set; }
    public bool PreviousEmployee { get; set; } 
    public List<Employee> GetEmployeeData(string code)
    {
        return new List<Employee>();
    }
}

Формат исходных данных имеет следующую структуру.то есть значение, возвращаемое из GetEmployeeData

FirstName | LastName    |   SSN         |   StartDate   |   DOB         | PreviousEmployee
------------------------------------------------------------------------------------------ 
Jane      | Smith       |   111111121   |   01/03/2018  |   01/01/1983  | true
John      | Smith       |   111111111   |   01/01/2018  |   01/01/1970  | true
Jeff      | Smith       |   111111122   |   01/03/2018  |   01/01/1983  | false

Теперь мне нужно преобразовать эти данные в файлы CSV (или некоторые в XML) с другой конфигурацией файлов.

Подобные примеры:

Некоторые форматы могут быть такими:

Формат 1:

FirstName,LastName,SSN,AppStartDate,AppDOB Jane,Smith,111111121,01/03/2018,01/01/1983 John,Smith,111111111,01/01/2018,01/01/1970 Jeff,Smith,111111122,01/03/2018,01/01/1983

Формат 2:

EMP_FIRST_NAME,EMP_LAST_NAME,EMP_SSN,EMP_DOB,EMP_JOB_START_DATE,PREV_EMPLOYED_BY_EMPLOYER Jane,Smith,111111121,01/03/2018,01/01/1983,Y John,Smith,111111111,01/01/2018,01/01/1970,Y Jeff,Smith,111111122,01/03/2018,01/01/1983,N

Формат в примерах отличается от типа Code.Формат имеет структуру, определяемую значением в коде.

Итак, есть ли какие-либо предложения для какого-либо общего пути к этому типу сценария?Или какие-нибудь предложения для некоторого образца?

Для преобразования в CSV я смотрю на эту тему

https://medium.com/@utterbbq/c-serializing-list-of-objects-to-csv-9dce02519f6b

Ответы [ 2 ]

0 голосов
/ 13 сентября 2018

Если вам не нравятся операторы switch и у вас есть какой-то статически типизированный ключ, вы можете использовать что-то вроде этого:

static readonly string _divider = ",";

static readonly Dictionary<string, (string header, Func<Employee, string[]> employee)> _configurations
            = new Dictionary<string, (string, Func<Employee, string[]>)>() {
                ["code1"] = ("FirstName,LastName,SSN,AppStartDate,AppDOB",
                        employee => new string[] {
                                    employee.FirstName,
                                    employee.LastName,
                                    employee.SSN,
                                    employee.StartDate,
                                    employee.DOB }),
                ["code2"] = ("EMP_FIRST_NAME,EMP_LAST_NAME,EMP_SSN,EMP_DOB,EMP_JOB_START_DATE,PREV_EMPLOYED_BY_EMPLOYER",
                        employee => new string[] {
                                    employee.FirstName,
                                    employee.LastName,
                                    employee.SSN,
                                    employee.DOB,
                                    employee.StartDate,
                                    employee.PreviousEmployee ? "Y" : "N" })
                    //...
                };

private string GetCSVResult( string code, List<Employee> employees )
        => _configurations[code].header
            + Environment.NewLine
            + employees.Select( e => _configurations[code]
                                     .employee( e )
                                     .Join( _divider ) )
                       .Join( Environment.NewLine );

Я использую это пользовательское расширение здесь:

public static class Extensions {
    public static string Join<T>( this IEnumerable<T> array, string divider = "," ) => string.Join( divider, array );
}

Также обратите внимание на статический словарь только для чтения.Возможно, вы захотите использовать Concurrent один вместо этого или использовать некоторый механизм блокировки для копирования и последующего выполнения (не уверен во всем этом, tbh).И он может быть включен в какой-то класс для более чистого просмотра (использование довольно чистое, вы можете избавиться от _divider, как мы говорим о C SV).

Это не оптимально(ни в памяти, ни в процессорах), нет кеша для тех же результатов и всего такого (и я уверен, что string [] результат не лучший способ для конкататации, независимо от того, можно ли когда-либо конкатировать строки;обратите внимание, что общая версия string.Join не является оптимальной).Это все зависит от вас, я надеюсь, что вы поняли идею со словарем.

Другой способ - использовать Reflection.Это не так быстро и приятно.ОД-убийственная магия с запахом шизофрении.Да, вы можете назначить атрибуты, а затем как-нибудь выполнить их, но в любом случае это уродливо (несколько атрибутов или множество аргументов для каждой конфигурации).

Есть несколько других способов «скомпилировать» эти функции, используя чистый ILили делегирует как сигнатуру + System.Linq.Expressions (это включает либо Reflection, но только в случае первого использования).

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

0 голосов
/ 13 сентября 2018

Я не эксперт по экспорту CSV, и было бы здорово иметь пример того, что вы пробовали в GetCSVResult.Но я думаю:

На всякий случай, если вы неправильно поняли вашу проблему, вы смотрели эти ссылки? Самый быстрый способ преобразовать список объектов в CSV с каждым значением объекта в новой строке и Преобразование универсального списка в строку CSV

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

public class ColumnCSV
{
    public int OriginalColumnIndex{ get; set; }
    public string Name { get; set; }
    public bool ExpectedInCSV { get; set; } 
}

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

...