繁体   English   中英

如何使用 .net 核心 API 将大型 CSV 文件导入到 SQL 服务器

[英]how to import large CSV file to SQL server using .net core API

如何导入大型 CSV 文件到 SQL 服务器使用.Net Core API (C#)

我试过下面的代码,它适用于少量数据,但我如何导入大量数据(csv 文件中大约 1000000 条记录)成块。

public void LoadFile()
    {

        string filePath = @"F:\Test\Book1.csv";
        using (var reader = new StreamReader(filePath))
        using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
        {
            var records = csv.GetRecords<SalesRecord>();
            foreach (var record in records)
            {

                SalesRecord _salesRecord = new SalesRecord();

                _salesRecord.Region = record.Region;
                _salesRecord.Country = record.Country;
                _salesRecord.ItemType = record.ItemType;
                _salesRecord.SalesChannel = record.SalesChannel;
                _salesRecord.OrderPriority = record.OrderPriority;
                _salesRecord.OrderDate = record.OrderDate;
                _salesRecord.OrderID = record.OrderID;
                _salesRecord.ShipDate = record.ShipDate;
                _salesRecord.UnitsSold = record.UnitsSold;
                _salesRecord.UnitPrice = record.UnitPrice;
                _salesRecord.UnitCost = record.UnitCost;
                _salesRecord.TotalRevenue = record.TotalRevenue;
                _salesRecord.TotalCost = record.TotalCost;
                _salesRecord.TotalProfit = record.TotalProfit;


                _context.SalesRecords.Add(_salesRecord);
            }
             _context.SaveChanges();
        }

   

EF Core 或任何其他 ORM 均不适用于批量导入。 它们旨在给人一种使用内存中对象的印象。 在 ETL/批量导入作业中,除了行、字段、转换之外,没有任何对象可以开始。 为了扩展,ETL 作业应该加载比必要更多的数据。 ORM 的缓存、查询和映射功能在这种情况下只是开销,增加了很大的延迟。 管理事务和批量大小(ETL 中最重要的考虑因素之一)非常困难,只能间接配置。

从客户端导入数据的最快方法是使用SqlBulkCopy 此 class 使用与 BCP 或 BULK INSERT 相同的协议来以最少的日志记录插入数据——这意味着仅记录数据页,而不记录单个 INSERT。

SqlBulkCopy 只接受 DataTable 或 IDbDataReader。 幸运的是,CsvHelper 提供了一个CsvDataReader接口,因此可以将行从 CSV 直接复制到数据库:

using (var reader = new StreamReader("path\\to\\file.csv"))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
    // Do any configuration to `CsvReader` before creating CsvDataReader.
    using (var dr = new CsvDataReader(csv))
    using (var con=new SqlConnection(connectionString))
    using (var bcp=new SqlBulkCopy(con))
    {
        bcp.DestinationTableName = "dbo.BulkCopyDemoMatchingColumns";
        con.Open();

        bcp.WriteToServer(reader);
    }
}

这将按 position 匹配源列和目标列,并期望数据类型匹配。 这必须在 CsvReader 的配置中完成。

在大多数情况下,源和目标列名称必须通过ColumnMappings集合按 position 或名称进行映射:

bcp.ColumnMappings("SourceA","TargetA");
bcp.ColumnMappings("SourceB","TargetB");

通过将EnableStreaming设置为 false,可以将 SqlBulkCopy 配置为读取 stream 中的数据。 默认情况下,它将缓存 memory 中的所有行,然后再将它们发送到服务器。 批量大小可以通过BatchSize属性进行配置。

SqlBulkCopy 可以每批使用一个事务,也可以对整个操作使用一个事务。 批处理和事务交互的方式在事务和批量复制操作中有解释。

构造函数中的SqlBulkCopyOptions参数可用于指定与BULK INSERT选项对应的其他重要设置,例如

  • 是否锁定目标表,增加性能
  • 是否触发触发器
  • 是否检查约束
  • 保留标识列值等。

导入任何 IEnumerable<>

SqlBulkCopy by using [FastMember's](https://github.com/mgravell/fast-member#ever-needed-an-idatareader) ObjectReader` 包装器,任何IEnumerable<T>集合都可以与 SqlBulkCopy 一起使用:

IEnumerable<SomeType> data = ... 

using(var bcp = new SqlBulkCopy(connection)) 
using(var reader = ObjectReader.Create(data)) 
{ 
  bcp.DestinationTableName = "SomeTable"; 
  bcp.WriteToServer(reader); 
}

暂无
暂无

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

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