繁体   English   中英

如何将列表中的数据导出为不同 CSV 格式的 CSV 文件

[英]How to export data from List to CSV files with different CSV format

我需要将报告上传到其他不同的系统,系统有他们自己接受的报告的预定义结构。 我们系统上的报告是根据用户选择的代码生成的。

用户不关心他们想在报表上导出的列,他们只需要从 UI 中选择code 我们的系统将参考code生成、下载正确格式的 CSV,并将其用作报告上传到另一个系统。

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方法中,我可以使用多个ifswitch-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)文件。

喜欢的例子:

一些格式可能是这样的:

格式一:

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

我不是 CSV 导出方面的专家,如果有一个您在 GetCSVResult 中尝试过的示例会很棒。 但是,我的猜测是:

以防万一误解了您的问题,您是否查看了这些链接? 使用新行中的每个对象值将对象列表转换为 csv并将通用列表转换为 CSV 字符串的最快方法

现在,如果我理解得很好,用户可以决定要导出或不导出的列,并在需要时更改其名称。 所以你可以有一个对象来描述这样一个列。 例如:

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

然后根据用户输入存储这些列的列表,您可以轻松编写一个可爱的开关来处理基于列索引的导出。

如果你不喜欢 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)。

它不是最佳的(无论是在内存上还是在 cpu 上),对于相同的结果和所有这些东西都没有缓存(而且我很确定 string[] 结果不是连接的最佳方式,无论连接是否可以)字符串;还要注意,string.Join 的通用版本并不是最佳的)。 这完全取决于你,我希望你能通过字典了解这个想法。

另一种方法是使用反射。 这样做并没有那么快和好。 带有精神分裂症气味的杀戮魔法。 是的,您可以分配属性,然后以某种方式执行它,但无论如何它都很丑陋(每个配置都有几个属性或大量参数)。

还有其他几种方法可以“编译”这个函数,使用纯 IL 或委托作为签名 + System.Linq.Expressions(它也涉及反射,但仅限于第一次使用)。

如果你想要一些真正干净的解决方案,你应该考虑使用注入实现和自定义脚本语言进行结构描述的抽象转换工厂,而不是对其进行硬编码。 但为什么? 此代码将返回有点正确的 CSV。 希望它会有所帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM