Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 如何将CsvHelper记录添加到DataTable中,以便将SqlBulkCopy用于数据库_.net_Csv_Datatable_Sqlbulkcopy_Csvhelper - Fatal编程技术网

.net 如何将CsvHelper记录添加到DataTable中,以便将SqlBulkCopy用于数据库

.net 如何将CsvHelper记录添加到DataTable中,以便将SqlBulkCopy用于数据库,.net,csv,datatable,sqlbulkcopy,csvhelper,.net,Csv,Datatable,Sqlbulkcopy,Csvhelper,我正在尝试使用CsvHelper读取CSV文件,将每条记录加载到数据表中,然后使用SqlBulkCopy将数据插入到数据库表中。对于当前代码,在向DataTable添加行时会出现异常。例外情况是:“无法将类型为“MvcStockAnalysis.Models.StockPrice”的对象强制转换为类型为“System.IConvertible”。无法存储在日期列中。预期类型为DateTime。” 示例CSV文件来自yahoo finance。例如: CSV文件包含以下标题: 日期开高关低关音量调

我正在尝试使用CsvHelper读取CSV文件,将每条记录加载到数据表中,然后使用SqlBulkCopy将数据插入到数据库表中。对于当前代码,在向DataTable添加行时会出现异常。例外情况是:“无法将类型为“MvcStockAnalysis.Models.StockPrice”的对象强制转换为类型为“System.IConvertible”。无法存储在日期列中。预期类型为DateTime。”

示例CSV文件来自yahoo finance。例如:

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");
    }
}
public-class-StockPriceClassMap:CsvClassMap
{
public override void CreateMap()
{
地图(m=>m.Date)。名称(“日期”);
Map(m=>m.Close).Name(“Close”);
Map(m=>m.AdjClose).Name(“Adj Close”);
地图(m=>m.High)。名称(“High”);
地图(m=>m.Low).Name(“Low”);
Map(m=>m.Open).Name(“Open”);
地图(m=>m.Volume).Name(“Volume”);
}
}
尝试将CsvHelper记录添加到数据表的代码如下所示:

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);
}
var connectionstring=ConfigurationManager.ConnectionStrings[“MvcStockAnalysis.Models.MvcStockAnalysisContext”];
var connection=newsqlconnection();
connection.ConnectionString=ConnectionString.ToString();
var destinationTableName=“股票价格”;
var company=db.company
.其中(c=>c.符号==“MMM”)
.FirstOrDefault();
尝试
{
字符串路径=HttpContext.Server.MapPath(“~/App_Data/”+company.Symbol+@.csv”);
if(System.IO.File.Exists(path))
{     
使用(StreamReader sr=新StreamReader(路径))
{
使用(var csv=新的CsvReader(sr))
{
数据表dt=新数据表(“股票价格”);
csv.Configuration.HasHeaderRecord=true;
csv.Configuration.RegisterClassMap();
添加(新数据列(“日期”,typeof(DateTime)));
添加(新数据列(“关闭”,类型为(双));
添加(新数据列(“AdjClose”,typeof(Double));
添加(新数据列(“高”,类型(双));
添加(新数据列(“低”,类型为(双));
添加(新数据列(“打开”,类型为(双));
添加(新数据列(“卷”,类型(双));
添加(新数据列(“CompanyId”,typeof(Double));
var records=csv.GetRecords().ToList();
foreach(记录中的var记录)
{                                    
record.CompanyId=公司Id;
dt.Rows.Add(记录);
}
//将dt添加到数据库中
使用(var bulkCopy=new SqlBulkCopy(connection.ConnectionString))
{
//DataTable列名与我的SQL列名匹配,所以我只做了这个循环。
foreach(dt.列中的数据列列列)
{
bulkCopy.ColumnMappings.Add(col.ColumnName,col.ColumnName);
}
bulkCopy.DestinationTableName=DestinationTableName;
bulkCopy.WriteToServer(dt);
}
}
}
}
connection.Close();
}
捕获(例外e)
{
控制台。写入(e.Message);
}

如何将CsvHelper记录添加到DataTable中,以便将SqlBulkCopy用于数据库?

我可以通过添加一个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);
}

如果你不需要太多的硬编码就可以解决这个问题,我会接受你的答案。

如果我没有弄错,你应该可以用更少的代码来解决。在进入
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 );
}

我喜欢@JoshClose的答案,但我发现
while(csv.Read())
csv.GetRecords().ToList()慢得多。当返回的值应为DBNull时,它也不能正确处理许多可为null的类型,如
int?
。我的答案是让CsvHelper导入一个动态记录列表,然后使用两个helper方法自动映射到DataTable

var records = csv.GetRecords<dynamic>().ToList();

foreach ( record in records )
{
    var row = dt.NewRow();

    var recordDictionary = DynamicToDictionary( record );

    foreach( DataColumn column in dt.Columns )
    {
        row[column.ColumnName] = GetColumnValue( column, recordDictionary );
    }

    dt.Rows.Add( row );
}
GetColumnValue
方法查找动态记录值并将其转换为正确的DataTable列值

public object GetColumnValue(DataColumn column, IDictionary<string, object> dynamicDictionary)
{
    object value;

    // Return DBNull if the column name isn't found.
    if (!dynamicDictionary.TryGetValue(column.ColumnName, out value))
    {
        return DBNull.Value;
    }

    // Null values come in as empty strings.
    if (column.AllowDBNull && column.DataType != typeof(string) && (string)value == "")
    {
        return DBNull.Value;
    }

    if (column.DataType == typeof(bool))
    {
        return (string)value != "0" && ((string)value).ToLower() != "false";
    }

    return value;
}
公共对象GetColumnValue(DataColumn列,IDictionary dynamicDictionary)
{
目标价值;
//如果未找到列名,则返回DBNull。
如果(!dynamicDictionary.TryGetValue(column.ColumnName,out值))
{
返回DBNull.Value;
}
//空值作为空字符串输入。
if(column.AllowDBNull&&column.DataType!=typeof(string)&&(string)值==“”)
{
返回DBNull.Value;
}
if(column.DataType==typeof(bool))
{
返回(字符串)值!=“0”&((字符串)值)。ToLower()!=“false”;
}
返回值;
}

Josh去年添加了对读取标题的支持,下面的代码块可能对那些只想使用CSV文档的模式构建数据表的人有用。我想把这篇文章作为对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;
    }

因为。。。你知道的。。。您是该库的作者如果有办法从映射中获取
索引(colName)
,当数据表列顺序与CSV顺序不匹配时会有所帮助。@JoePhillips那又怎样?一个图书馆的作者不能回答一个问题吗?@StefanFachmann是的
    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;
    }