使用CSVHelper .NET库和.NET Core 2.2来解析大型csv文件(超过一百万行)并将其写入SQL Server表中。
我有两个映射类:我们需要遍历每一行,并且如果该行的第一个值为1,则需要使用类映射1,如果值是2,则需要使用类映射2 。由于CSVHelper旨在批量进行此活动,因此在概念化如何使用if
语句和for each
循环来完成此任务方面遇到困难。
这是我到目前为止所拥有的:
SQL实体类
public class TaskEntity
{
public int Id { get; set; }
public string SqlTableColumn1 { get; set; }
public string SqlTableColumn2 { get; set; }
}
CSVHelper映射类1
public sealed class TaskEntityMap1 : ClassMap<TaskEntity>
{
public TaskEntityMap1()
{
Map(m => m.SqlTableColumn1).Name("CsvColumn1");
Map(m => m.SqlTableColumn2).ConvertUsing(row => row.GetField<string>("CsvColumn2") + " " + row.GetField<string>("CsvColumn3"));
}
}
CSVHelper映射类2
public sealed class TaskEntityMap2 : ClassMap<TaskEntity>
{
public TaskEntityMap2()
{
Map(m => m.SqlTableColumn1).Name("CsvColumn4");
Map(m => m.SqlTableColumn2).ConvertUsing(row => row.GetField<string>("CsvColumn5") + " " + row.GetField<string>("CsvColumn6"));
}
}
Program.cs (这是我们之前收到的条件映射要求)
public static void Main(string[] args)
{
using (var reader = new StreamReader(@"C:\Users\me\Documents\file.csv"))
using (var csv = new CsvReader(reader))
{
csv.Configuration.PrepareHeaderForMatch = (string header, int index) =>
header.Replace(" ", "_").Replace("(", "").Replace(")", "").Replace(".", "");
csv.Configuration.RegisterClassMap<TaskEntityMap>();
var records = csv.GetRecords<TaskEntity>().ToList();
}
}
如上面的Program.cs
代码示例所示,该典型的易用方案似乎是CSVHelper设计的,我在概念上很难理解如何使用两个类映射以及如何遍历csv文件的每一行,然后根据给定行中一列中的值选择类映射。
答案 0 :(得分:1)
当我最初听到您的要求时,我认为您只需要为每个文档检查一次ClassMap
。现在听起来好像每行都会改变。不幸的是,我发现一旦您注册并开始使用ClassMap
,它似乎就会被缓存,并且您无法将其切换到一半,因此我认为这两个ClassMaps
不会起作用。我会给您几种解决方法,您可以让我知道其中一个是否满足您的要求。
public static void Main(string[] args)
{
using (var reader = new StreamReader(@"C:\Users\me\Documents\file.csv"))
using (var csv = new CsvReader(reader))
{
csv.Configuration.PrepareHeaderForMatch = (string header, int index) =>
header.Replace(" ", "_").Replace("(", "").Replace(")", "").Replace(".", "");
csv.Configuration.RegisterClassMap<TaskEntityMap>();
var records = csv.GetRecords<TaskEntity>().ToList();
}
}
public sealed class TaskEntityMap : ClassMap<TaskEntity>
{
public TaskEntityMap()
{
Map(m => m.SqlTableColumn1).ConvertUsing(row => row.GetField<int>(0) == 1 ?
row.GetField<string>("CsvColumn1") :
row.GetField<string>("CsvColumn4")
);
Map(m => m.SqlTableColumn2).ConvertUsing(row => row.GetField<int>(0) == 1 ?
row.GetField<string>("CsvColumn2") + " " + row.GetField<string>("CsvColumn3") :
row.GetField<string>("CsvColumn5") + " " + row.GetField<string>("CsvColumn6")
);
}
}
另一种选择是手动构造TaskEntity
对象。
public static void Main(string[] args)
{
using (var reader = new StreamReader(@"C:\Users\me\Documents\file.csv"))
using (var csv = new CsvReader(reader))
{
csv.Configuration.PrepareHeaderForMatch = (string header, int index) =>
header.Replace(" ", "_").Replace("(", "").Replace(")", "").Replace(".", "");
var records = new List<TaskEntity>();
csv.Read();
csv.ReadHeader();
while (csv.Read())
{
if (csv.GetField<int>(0) == 1)
{
var record = new TaskEntity
{
SqlTableColumn1 = csv.GetField<string>("CsvColumn1"),
SqlTableColumn2 = csv.GetField<string>("CsvColumn2") + " " + csv.GetField<string>("CsvColumn3")
};
records.Add(record);
}
else
{
var record = new TaskEntity
{
SqlTableColumn1 = csv.GetField<string>("CsvColumn4"),
SqlTableColumn2 = csv.GetField<string>("CsvColumn5") + " " + csv.GetField<string>("CsvColumn6")
};
records.Add(record);
}
}
} // Break here.
}