Jus*_*afe 10 .net csv datatable sqlbulkcopy csvhelper
我试图用CsvHelper读取CSV文件,将每个记录加载到DataTable,然后使用SqlBulkCopy将数据插入数据库表.使用当前代码,在向DataTable添加行时会出现异常.例外情况是:"无法将'MvcStockAnalysis.Models.StockPrice'类型的对象强制转换为'System.IConvertible'.不能存储在日期列中.预期的类型是DateTime."
示例CSV文件来自yahoo finance.例如:http://ichart.yahoo.com/table.csv?s = MMM&a = 0&b = 1&c = 2010&d = 0&e = 17&f = 2014&g = d&signore = .cv
CSV文件包含以下标题:日期打开高低关闭音量调整关闭
我正在将CSV文件读入的模型:
namespace MvcStockAnalysis.Models
{
    using System;
    using System.Collections.Generic;
    public partial class StockPrice
    {
        public int Id { get; set; }
        public System.DateTime Date { get; set; }
        public int CompanyId { get; set; }
        public double High { get; set; }
        public double Low { get; set; }
        public double Close { get; set; }
        public double AdjClose { get; set; }
        public double Open { get; set; }
        public double Volume { get; set; }
        public virtual Company Company { get; set; }
    }
}
CSV文件到StockPrice类的映射使用以下内容:
public class StockPriceClassMap : CsvClassMap<StockPrice>
{
    public override void CreateMap()
    {
        Map(m => m.Date).Name("Date");
        Map(m => m.Close).Name("Close");
        Map(m => m.AdjClose).Name("Adj Close");
        Map(m => m.High).Name("High");
        Map(m => m.Low).Name("Low");
        Map(m => m.Open).Name("Open");
        Map(m => m.Volume).Name("Volume");
    }
}
尝试将CsvHelper记录添加到DataTable的代码如下:
var connectionstring = ConfigurationManager.ConnectionStrings["MvcStockAnalysis.Models.MvcStockAnalysisContext"];
var connection = new SqlConnection();
connection.ConnectionString = connectionstring.ToString();
var destinationTableName = "StockPrices";
var company = db.Company
            .Where(c => c.Symbol == "MMM")
            .FirstOrDefault();
try
{
    string path = HttpContext.Server.MapPath("~/App_Data/" + company.Symbol + @".csv");
    if (System.IO.File.Exists(path))
    {     
        using (StreamReader sr = new StreamReader(path))
        {
            using (var csv = new CsvReader(sr))
            {
                DataTable dt = new DataTable("StockPrices");
                csv.Configuration.HasHeaderRecord = true;
                csv.Configuration.RegisterClassMap<StockPriceClassMap>();
                dt.Columns.Add(new DataColumn("Date", typeof(DateTime)));
                dt.Columns.Add(new DataColumn("Close", typeof(Double)));
                dt.Columns.Add(new DataColumn("AdjClose", typeof(Double)));
                dt.Columns.Add(new DataColumn("High", typeof(Double)));
                dt.Columns.Add(new DataColumn("Low", typeof(Double)));
                dt.Columns.Add(new DataColumn("Open", typeof(Double)));
                dt.Columns.Add(new DataColumn("Volume", typeof(Double)));
                dt.Columns.Add(new DataColumn("CompanyId", typeof(Double)));
                var records = csv.GetRecords<StockPrice>().ToList();
                foreach (var record in records)
                {                                    
                    record.CompanyId = company.Id;
                    dt.Rows.Add(record);
                }
                // add dt to the database
                using (var bulkCopy = new SqlBulkCopy(connection.ConnectionString))
                {
                    // DataTable column names match my SQL Column names, so I simply made this loop. 
                    foreach (DataColumn col in dt.Columns)
                    {
                        bulkCopy.ColumnMappings.Add(col.ColumnName, col.ColumnName);
                    }
                    bulkCopy.DestinationTableName = destinationTableName;
                    bulkCopy.WriteToServer(dt);
                }
            }
        }
    }
    connection.Close();
}
catch (Exception e)
{
    Console.Write(e.Message);
}
如何将CsvHelper记录添加到DataTable以用于SqlBulkCopy到数据库?
Jos*_*ose 19
如果我没有弄错的话,你应该可以用更少的代码来做.在进入其中之前,您不必进入另一个类DataTable.
while( csv.Read() )
{
    var row = dt.NewRow();
    foreach( DataColumn column in dt.Columns )
    {
        row[column.ColumnName] = csv.GetField( column.DataType, column.ColumnName );
    }
    dt.Rows.Add( row );
}
Josh 去年增加了对读取标题的支持,以下块可能对那些只想使用 CSV 文档架构构建 DataTable 的人有用。我想将此作为对 Josh 答案的评论发布,因为它只是一个小的修改,但作为答案发布,因为我无法在评论中格式化代码块。
    private DataTable BuildDataTable()
    {
        var dt = new DataTable();
        using (var textReader = new StreamReader(_path))
        {
            using (var csv = new CsvReader(textReader))
            {
                csv.ReadHeader();
                foreach (var header in csv.FieldHeaders)
                {
                    dt.Columns.Add(header);
                }
                while (csv.Read())
                {
                    var row = dt.NewRow();
                    foreach (DataColumn column in dt.Columns)
                    {
                        row[column.ColumnName] = csv.GetField(column.DataType, column.ColumnName);
                    }
                    dt.Rows.Add(row);
                }
            }
        }
        return dt;
    }
我能够通过添加 DataTable 行并显式填充它来使其工作,而不是尝试将 CsvHelper 记录添加为行。
我使用以下部分而不是上面显示的类似部分:
foreach (var record in records)
{
    DataRow row = dt.NewRow();
    record.CompanyId = company.Id;
    row["Date"] = record.Date;
    row["Close"] = record.Close;
    row["AdjClose"] = record.AdjClose;
    row["High"] = record.High;
    row["Low"] = record.Low;
    row["Open"] = record.Open;
    row["Volume"] = record.Volume;
    row["CompanyId"] = record.CompanyId;
    dt.Rows.Add(row);
}
如果您不需要那么多硬编码就能解决问题,我会接受您的答案作为答案。