【问题标题】:CsvHelper - write to SQL Database with mappingCsvHelper - 使用映射写入 SQL 数据库
【发布时间】:2019-09-27 21:09:43
【问题描述】:

到目前为止,CSVHelper .NET 库看起来很棒,但是对于像我这样的伪初学者来说,文档有点缺乏。

我需要读取一个 csv 文件并将结果写入我们的 SQL Server 数据库。对于我正在写入的表,我需要从 CSV 列映射到它的列,包括将多个字段连接到一个。

这是我用来读取 csv 文件的内容:

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 = csv.GetRecords<EntityCsv>().ToList();
    }
}

我的 EntityCsv 类包含 csv 文件所有列的属性名称。

然后,我还有一个名为 TaskEntity 的类,其中包含目标数据库表的属性名称和类型(尽管我不清楚是否需要它)。

最后,根据同事的建议,我设置了一个方法来使用SQLBulkCopy,如下所示:

public void AddBulk(List<TaskEntity> entities)
{
    using (var con = GetConnection())
    {
        SqlBulkCopy bulk = new SqlBulkCopy(con);
        bulk.BatchSize = 2000;
        bulk.BulkCopyTimeout = 0;
        bulk.DestinationTableName = "dbo.CsvExports";
        bulk.WriteToServer(entities.AsDataTable());
        bulk.Close();
    }
}

我从他那里借了那个代码块,理论上会在最后一步运行那个方法。

但我知道我在两者之间缺少了一步,那就是将字段从 csv 映射到 SQL 服务器字段。我正在为如何实现这一步而摸不着头脑。

为了简单起见,假设我在 csv 文件中有 3 列,我想将它们映射到 SQL 表的 2 列,如下所示:

CsvColumn1 -> SQLtableColumn1
CsvColumn2 + CsvColumn3 -> SQLtableColumn2

我将如何使用 CsvReader 和 C# 来完成此任务?我已经探索了 CSVReader 文档的映射部分,但我在那里看到的所有内容似乎都是指将输入文件中的列名映射到输出文件中的名称。我在那里(Google 上的任何地方)都没有看到任何专门用于获取输入文件并将其行导出到 SQL 数据库的内容。

【问题讨论】:

    标签: c# csvhelper


    【解决方案1】:

    您可以使用 ClassMap 将 csv 列映射到 sql 表列并跳过 CsvEntity 类。

    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 class TaskEntity
    {
        public int Id { get; set; }
        public string SqlTableColumn1 { get; set; }
        public string SqlTableColumn2 { get; set; }
    }
    
    public sealed class TaskEntityMap : ClassMap<TaskEntity>
    {
        public TaskEntityMap()
        {
            Map(m => m.SqlTableColumn1).Name("CsvColumn1");
            Map(m => m.SqlTableColumn2).ConvertUsing(row => row.GetField<string>("CsvColumn2") + " " + row.GetField<string>("CsvColumn3"));
        }
    }
    

    【讨论】:

    • 很高兴再次见到你,大卫。这看起来像是我一直在寻找的答案。让我确保它有效,如果是这样,我会将其标记为答案,以便您获得赏金。谢谢!
    • 嗨大卫,我刚刚遇到了一件我没有考虑过的事情 - 我很确定你的解决方案会奏效,无论如何我都会奖励你 - 快速提问:假设我创建了两个不同的实体映射,TaskEntityMap1TaskEntityMap2;然后说,在 csv 文件中,如果给定行的第一个字段是 1,则使用 TaskEntityMap1 将该行映射到 SQL,如果是 2,则使用 TaskEntityMap2。两个映射都会映射到同一个 SQL 表,只是转到不同的字段。当我使用 CSVHelper 时,我将在哪里处理代码中的逻辑,因为不涉及 for each 循环?
    • 您可能需要遍历每条记录,以便检查第一条记录的映射标志。查看Reading By Hand 上的文档我会做一个Read()ReadHeader()、另一个Read(),然后按名称或索引检查您的标志字段。注册特定的ClassMap。调用 GetRecord&lt;TaskEntity&gt; 添加该记录(而不是添加每个单独的属性),然后启动您的 while(csv.Read()) 循环以获取其余记录。如果您需要更多,只需开始一个新的 StackOverflow 问题。
    • 嗨大卫,谢谢,这是一个很好的观点,我应该开始一个新问题。我会去做。看来您上面的答案实际上确实满足了原始问题,所以很快我将其标记为答案,以奖励您。再次感谢!
    • 大卫,如果你有兴趣的话:stackoverflow.com/questions/58190364/…
    【解决方案2】:

    我使用 SqlBulkCopycsvhelper 将数据转储到 sql 服务器。

    SqlBulkCopy 是一个很棒的实用程序,它可以从几乎任何可以加载到 DataTable 实例中的数据源将数据写入 sql 服务器。

    var lines = File.ReadAllLines(file);
    if (lines.Count() == 0) 
        return;
    
    var tableName = GetTableName(file);
    var columns = lines[0].Split(',').ToList();
    var table = new DataTable();
    sqlBulk.ColumnMappings.Clear();
    
    foreach (var c in columns)
    {
        table.Columns.Add(c);
        sqlBulk.ColumnMappings.Add(c, c); 
    }
    
    for (int i = 1; i < lines.Count() - 1; i++)
    {
        var line = lines[i];
        // Explicitly mark empty values as null for SQL import to work
        var row = line.Split(',')
            .Select(a => string.IsNullOrEmpty(a) ? null : a).ToArray();
        table.Rows.Add(row);
    }
    
    sqlBulk.DestinationTableName = tableName;
    sqlBulk.WriteToServer(table);
    

    【讨论】:

      猜你喜欢
      • 2014-05-09
      • 1970-01-01
      • 2015-12-12
      • 2022-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-21
      相关资源
      最近更新 更多