【问题标题】:Handling DateTime fields from CsvDataReader that contains an empty string处理来自 CsvDataReader 的包含空字符串的 DateTime 字段
【发布时间】:2019-05-08 20:19:35
【问题描述】:

我正在尝试使用 CsvHelper 从 CSV 文件加载数据,以创建具有指定类型的数据列的数据表。

                var textReader = new StreamReader(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{tableName}.csv"));
                var csvReader = new CsvReader(textReader);
                var csvDataReader = new CsvDataReader(csvReader);
                var dataTable = new DataTable();
                foreach(var column in metaColumns)
                {               

                    var dataColumn = new DataColumn(column.columnName, GetPropertyType(column.dataType));
                    dataColumn.AllowDBNull = column.isNull;
                    dataTable.Columns.Add(dataColumn);
                }

                dataTable.Load(csvDataReader);

在加载方法上出现以下错误:

String '' 未被识别为有效的 DateTime。无法将 存储在 derived_mdd_date 列。预期类型为 DateTime。

显然 CsvHelper 正在将 CSV 文件中的列作为空字符串加载,然后当给定 DateTime 类型时,它不会将空字符串转换为空值。

经过一些研究并尝试了我添加的东西

            csvReader.Configuration.TypeConverterOptionsCache.GetOptions<DateTime>().NullValues.Add("null");
            csvReader.Configuration.TypeConverterOptionsCache.GetOptions<DateTime?>().NullValues.Add("null");
            csvReader.Configuration.TypeConverterOptionsCache.GetOptions<string>().NullValues.Add("null");
            csvReader.Configuration.TypeConverterCache.AddConverter<DateTime>(new DateFieldConverter());
            csvReader.Configuration.TypeConverterCache.AddConverter<DateTime?>(new DateFieldConverter());
...
    public class DateFieldConverter : DateTimeConverter
    {
        public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
        {
            bool result = DateTime.TryParse(text, out DateTime ret);
            if (result) return ret;
            return null;
        }
    }

仍然遇到同样的错误。我在 DateFieldConverter 上放置了一个断点,它永远不会被击中,所以有些东西没有正确同步。我认为 DateTime 列的默认行为是 DateTime.MinValue 或 null 但它只是抛出错误。

【问题讨论】:

    标签: c# datatable csvhelper


    【解决方案1】:

    不幸的是,CsvDataReader 似乎将所有值都视为字符串,而忽略了其他类型的 TypeConverters。似乎有一个feature request 来添加该功能。

    我可以提供一个可能对您有用的解决方法。您也可以查看我的answer here 以获取其他选项。

    public static void Main(string[] args)
    {
        using (MemoryStream stream = new MemoryStream())
        using (StreamWriter writer = new StreamWriter(stream))
        using (StreamReader reader = new StreamReader(stream))
        using (CsvReader csv = new CsvReader(reader))
        {
            writer.WriteLine("DateTime,DateTimeNullable");
            writer.WriteLine("5/4/2019,");
            writer.WriteLine(",5/5/2019");
            writer.Flush();
            stream.Position = 0;
    
            csv.Configuration.TypeConverterCache.AddConverter<DateTime>(new DateFieldConverter());
            csv.Configuration.TypeConverterCache.AddConverter<DateTime?>(new DateFieldNullableConverter());
    
            var dataTable = new DataTable();
            dataTable.Columns.Add("DateTime", typeof(DateTime)).AllowDBNull = false;
            dataTable.Columns.Add("DateTimeNullable", typeof(DateTime)).AllowDBNull = true;
    
            csv.Read();
            csv.ReadHeader();
            while (csv.Read())
            {
                var row = dataTable.NewRow();
                foreach (DataColumn column in dataTable.Columns)
                {
                    if (column.DataType == typeof(DateTime) && column.AllowDBNull)
                    {
                        row[column.ColumnName] = csv.GetField(typeof(DateTime?), column.ColumnName);
                    }
                    else
                    {
                        row[column.ColumnName] = csv.GetField(column.DataType, column.ColumnName);
                    }                        
                }
                dataTable.Rows.Add(row);
            }                
        }
    }
    
    public class DateFieldConverter : DateTimeConverter
    {
        public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
        {
            if (text == string.Empty)
            {
                return DateTime.MinValue;
            }
    
            return base.ConvertFromString(text, row, memberMapData);                
        }
    }
    
    public class DateFieldNullableConverter : DateTimeConverter
    {
        public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
        {
            if (text == string.Empty)
            {
                return DBNull.Value;
            }
    
            return base.ConvertFromString(text, row, memberMapData);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-06-01
      • 1970-01-01
      • 2015-05-13
      • 2012-06-03
      • 2013-03-17
      • 2014-05-04
      • 1970-01-01
      • 1970-01-01
      • 2020-02-27
      相关资源
      最近更新 更多